隨筆 - 2  文章 - 2  trackbacks - 0
          <2025年6月>
          25262728293031
          1234567
          891011121314
          15161718192021
          22232425262728
          293012345

          留言簿

          隨筆檔案(1)

          文章分類(16)

          最新隨筆

          搜索

          •  

          最新評論

          在應用的 dispatcher-servlet.xml 中添加如下配置:
              <bean id="velocityConfigurer" class="org.springframework.web.servlet.view.velocity.VelocityConfigurer">
                  
          <property name="resourceLoaderPath"><!-- 頁面文件的路徑,相對于webapp -->
                      
          <value>templates</value>
                  </property>
                  
          <!-- Velocity屬性配置 -->
                  
          <property name="velocityProperties">
                      
          <props>
                          
          <prop key="input.encoding">UTF-8</prop><!-- 指定模板引擎進行模板處理的編碼 -->
                          
          <prop key="output.encoding">UTF-8</prop><!-- 指定輸出流的編碼 -->
                          
          <prop key="contentType">text/html;charset=UTF-8</prop><!-- contentType -->
                          
          <prop key="velocimacro.library">macro/macros.vm</prop><!-- Velocimacro 模板庫的列表 -->
                          
          <prop key="eventhandler.referenceinsertion.class">com.sde.common.web.escape.reference.NoEscapeHtmlReference</prop>
                          
          <prop key="eventhandler.noescape.html.match">/(?:screen_content)|(?:noescape_.*)/</prop>
                      
          </props>
                  
          </property>
              
          </bean>

              
          <bean id="viewResolver" class="org.springframework.web.servlet.view.velocity.VelocityLayoutViewResolver">
                   
          <property name="cache" value="false" /><!--是否緩存模板-->
                    
          <property name="prefix" value="" />
                   
          <property name="suffix" value=".vm" />
                   
          <property name="toolboxConfigLocation" value="/WEB-INF/toolbox.xml" /><!--toolbox配置文件路徑-->
                    <property name="dateToolAttribute" value="date" /><!--日期函數名稱-->
                    <property name="numberToolAttribute" value="number" /><!--數字函數名稱-->
                   
          <property name="contentType" value="text/html;charset=UTF-8" />
                    
          <property name="exposeSpringMacroHelpers" value="true" /><!--是否使用spring對宏定義的支持-->        
                    <property name="exposeRequestAttributes" value="true" /><!--是否開放request屬性-->
           
                   <property name="requestContextAttribute" value="rc"/><!--request屬性引用名稱-->
                       <property name="layoutUrl" value="templates/layout/default.vm"/<!--指定layout文件-->
             </bean>
          posted @ 2011-11-24 15:57 liucs 閱讀(6607) | 評論 (0)編輯 收藏

          一、概述

          SpringMVC在2.5版本后新增了注解功能,2.5版本以前的基本通過繼承Controller體系來開發業務控制器,2.5版本后Controller體系中
          BaseCommandController及其子類AbstractCommandController、AbstractFormController、AbstractWizardFormController、
          SimpleFormController、CancellableFormController等都已經被標示為@Deprecated,建議不再使用。

          相比傳統的繼承Controller體系中某些類的方式,SpringMVC的注解具有以下優點:
          1、Controller不再需要繼承某個特定類,只是簡單的POJO。
          2、請求映射的配置非常方便靈活。
          3、參數綁定機制非常方便豐富。
          4、可以根據不同的http方法或者參數,細粒度處理不同的http請求

          二、示例

          下面通過對SpringMVC注解的詳細介紹來看一下上述優點。

          首先需要在應用的dispatcher-servlet.xml 啟動注解機制
          <context:annotation-config />
          <!-- 設置注解驅動 -->
          <mvc:annotation-driven />
           
          <!-- 設置掃描的包 -->
          <context:component-scan base-package="com.demo.web.controller" />
          <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
          <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

          注:雖然我們的Controller不需要再繼承任何類,但出于規范,我們仍然命名為***Controller.java,并統一放在com.demo.web.controller包中。

          1、@Controller注解

          簡單示例
          package com.demo.controller;

          import org.springframework.stereotype.Controller;
          import org.springframework.web.bind.annotation.RequestMapping;

          @Controller
          class IndexController {
              @RequestMapping(
          "/index")
              String index() {
                  
          return "index";
              }
          }

          在一個POJO上面使用 @Controller 就可以標注該POJO是一個Controller,就這么簡單。 @Controller注解定義在org.springframework.steretype包中。
          使用方式: @Controller 或者 @Controller("indexController)。 org.springframework.steretype包中還包含 @Componenet @Service @Respository
          三個注解。@Component是通用標注,@Controller標注web控制器,@Service標注Servicec層的服務,@Respository標注DAO層的數據訪問。

          2、使用@RequestMapping注解處理請求映射

              SpringMVC中注解基本都包含在 org.springframework.web.bind.annotation 包中。先看一下@RequestMapping 注解的源碼。
          @Target( { ElementType.METHOD, ElementType.TYPE })
          @Retention(RetentionPolicy.RUNTIME)
          @Documented
          @Mapping
          public @interface RequestMapping {

              
          /**
               * 指定映射的URL.可以在類層次和方法層次使用。方式如下:
               * @RequestMapping("/add_")或 @RequestMapping(value = "/add")
               * 支持Ant風格的URL映射,如 @RequestMapping("/myPath/*.htm")
               * 在類層次指定了映射后,可以在方法層次再指定相對路徑
               
          */
              String[] value() 
          default {};

              
          /**
               * 指定HttpRequest的方法, 如:GET, POST, HEAD, OPTIONS, PUT, DELETE, TRACE.
               * 使用舉例: @RequestMapping(value = "/add_activity", method = RequestMethod.GET)
               
          */
              RequestMethod[] method() 
          default {};

              
          /**
               * 指定HttpRequest中包含的參數,使用方式如下:
               * @RequestMapping(value = "/something",params="myParam") 請求包含myParam參數
               * @RequestMapping(value = "/something",params="myParam=myValue")請求包含myParam參數,并且該參數值為myValue
               * @RequestMapping(value = "/something",params="!myParam") 請求不包含myParam參數
               
          */
              String[] params() 
          default {};

              
          /**
               * 指定HttpRequest中包含的頭部信息,使用方式如下:
               * @RequestMapping(value = "/something", headers="content-type")請求包含該頭部
               * @RequestMapping(value = "/something", headers="content-type=text/*")請求包含特定值的頭部
               * @RequestMapping(value = "/something", headers="!content-type")請求不包含該頭部
               
          */
              String[] headers() 
          default {};

          }
          注:如果在類層次指定了映射,則方法層次上都將繼承類層次的映射

          3、獲取HttpRequest中得參數

          @RequestMapping("active")
          public @ResponseBody boolean active(Long accountId) {
              return accountService.activeAccount(accountId);
          }

          @RequestMapping("active")
          public @ResponseBody boolean active(Account account) {
              return accountService.activeAccount(accountId);
          }
          @RequestMapping(
          "inactive")
          public @ResponseBody boolean inactive(@RequestParam("accountId") Long accountId,
                      @RequestHeader(
          "User-Agent") String userAgent,
                      @CookieValue(
          "loginId") String loginId) {
              
          return accountService.inactiveAccount(accountId);
          }

          @RequestMapping(value 
          = "list/{pageNo}", method = RequestMethod.GET)
          public String list(@PathVariable int pageNo) {
               
          return "/account/list";
          }

          @RequestMapping(value = "add", method = RequestMethod.GET)
          public String add(@RequestBody String body) {
               return "/account/add";
          }


          active方法的入參 accountId,如果請求中有名為 accountId的參數,則會進行默認綁定,不僅基本類型,javabean的屬性也可以默認進行綁定;
          如果需要明確綁定,使用@RequestParam。 一般建議進行明確指定。

          3.1 @RequestParam 綁定httpRequest中參數,@RequestParam("accountId") 完整形式為  @RequestParam(value="accountId",required=true,defaultValue=null)
          3.2 @RequestHeader 綁定httpRequest頭部信息,@RequestHeader("User-Agent") 完整形式為 @RequestHeader(value="User-Agebt",required=true, defaultValue=null)
          3.3 @CookieValue 綁定一個Cookie值,@CookieValue("loginId") 完整形式為 @CookieValue(value="loginId",required=true,defaultValue=null)
          3.4 @RequestBody 將httpRequest的body綁定到方法參數上
          3.5 @ModelAttribute 有兩種使用方式: 1)在方法級別,指定方法的返回值綁定到model中; 2)方法參數級別,指定model中的值綁定到方法的入參上 示例如下:
           @ModelAttribute("countryList")
              
          public List<String> getCountries() {
                  
          return new ArrayList<String>();
              }

          @RequestMapping(value 
          = "search", method = RequestMethod.POST)
              
          public String searchAccount(@ModelAttribute("accountId") Long accountId) {
                  
          return "/search";
              }

          4、使用@ResponseBody 生成response

              適用于webservice的數據交換,或ajax異步請求,text、json或者xml格式的數據交換。
              例如訪問: http://localhost:8080/accounts/info.htm
           

          @RequestMapping(value = "info")
          public @ResponseBody Account getAccount() {
                  Account a 
          = new Account();
                  a.setId(
          123L);
                  a.setName(
          "zhangsan");
                  
          return a;
           }

          返回數據如下:
          {"name":"zhangsan","id":123}
          從上面例子可以看出,使用@ResponseBody后,返回的javabean默認被序列化成json格式的數據并被寫入到response body中。

          @Request 和 @ReponseBody 使用了HttpMessageConverter機制。下面是HttpMessageConverter的繼承體系。


          常用的有如下幾個:
          StringHttpMessageConverter ---字符串
          MappingJacksonHttpMessageConverter ----json
          ByteArrayHttpMessageConverter ----字節數組
          MarshallingHttpMessageConverter -----xml

          5、使用模板技術生成response

              適用于一般頁面請求。可以使用velocity freemarker等模板技術,在dispatcher-servlet.xml中需要設置viewResolver。
             

          @RequestMapping("/index")
          public String index(ModelMap modelMap) {
                  modelMap.put(
          "name""liucs");
                  
          return "index";
          }

          @RequestMapping(
          "/index")
          public String index2(Model model) {
                  model.addAttribute(
          "name","liucs");
                  
          return "index";
          }

          @RequestMapping("/index")
          public ModelAndView index3() throws Exception {
                ModelAndView mav = new ModelAndView("index");
                mav.addObject("name", "liucs");
                return mav;
          }

          如上面代碼index1和index2所示,不使用@ResponseBody注解。 返回一個String類型,這個String是viewname, 如果是重定向,return "redirect:/index.htm".
          入參可以包含ModelMap或者Model,其實這兩者是一個東西,作用一樣。也可以采用index3式的傳統寫法,返回一個ModelAndView對象。

          6、數據驗證

          @InitBinder標注
          @InitBinder
              
          public void myInitBinder(WebDataBinder binder){
                binder.setDisallowedFields(
          new String[]{"id"});
              }
          通過在方法中聲明一個BindingResult參數來啟動綁定和驗證
          @RequestMapping("update")
              
          public void update(@ModelAttribute("account") Account account,BindingResult bindResult) {
                  
          if(bindResult.hasErrors()){
                      
          //……
                  }
              }
          需要注意以下限制:
          1、BindingResult參數必須跟在一個JavaBean參數后面
          2、錯誤會被自動的綁定到model中,便于渲染模板時使用
          3、不支持@RequestBody等類型的參數形式

          7、異常處理

          @ExceptionHandler


          posted @ 2011-09-05 16:42 liucs 閱讀(8517) | 評論 (2)編輯 收藏

          Annotation(注解)是什么?

          附加在代碼中的一些元信息,用于一些工具在編譯、運行時進行解析和使用,起到說明、配置的功能。
          注解不會也不能影響代碼的實際邏輯,僅僅起到輔助性的作用。包含在 java.lang.annotation 包中。

          1、Annotation的定義

          首先看一下如何定義我們自己的注解,下面是SpringMvc中RequestParam注解的定義。
          @Retention(RetentionPolicy.RUNTIME) // 注解的保留策略
          @Target(ElementType.PARAMETER)  // 注解的作用目標
          @Documented
          public @interface RequestParam {  // 使用@interface定義注解
              String value() 
          default "";  // 類似方法的屬性
              
          boolean required() default true;  // 使用default指定屬性的默認值
              String defaultValue() 
          default ValueConstants.DEFAULT_NONE;
          }

          使用方式如下:
          void deleteUser(@RequestParam(value="id",required=false) Long id)  { }

          2、元注解

          元注解是指注解的注解。包括  @Retention @Target @Document @Inherited四種。

          2.1、@Retention: 定義注解的保留策略

          @Retention(RetentionPolicy.SOURCE)   注解僅存在于源碼中,在class字節碼文件中不包含
          @Retention(RetentionPolicy.CLASS)      默認的保留策略,注解會在class字節碼文件中存在,但運行時無法獲得,
          @Retention(RetentionPolicy.RUNTIME)   注解會在class字節碼文件中存在,在運行時可以通過反射獲取到

          2.2、@Target:定義注解的作用目標

          @Target(ElementType.TYPE)   接口、類、枚舉、注解
          @Target(ElementType.FIELD)  字段、枚舉的常量
          @Target(ElementType.METHOD)  方法
          @Target(ElementType.PARAMETER) 方法參數
          @Target(ElementType.CONSTRUCTOR)  構造函數
          @Target(ElementType.LOCAL_VARIABLE) 局部變量
          @Target(ElementType.ANNOTATION_TYPE) 注解
          @Target(ElementType.PACKAGE)     

          2.3、@Document:說明該注解將被包含在javadoc中

          2.4、@Inherited:說明子類可以繼承父類中的該注解

          3、通過反射讀取注解


          package java.lang.reflect;
          import java.lang.annotation.Annotation;

          public interface AnnotatedElement {
              
          /**判斷該元素中某個注解類型是否存在*/
               
          boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);

             
          /**獲得該元素中某個注解類型的注解*/
              
          <extends Annotation> T getAnnotation(Class<T> annotationClass);

              
          /**獲得該元素中所有可見的注解,包含繼承得到的注解*/
              Annotation[] getAnnotations();

              
          /**獲得該元素自身什么的注解,不包含繼承得到的注解*/
              Annotation[] getDeclaredAnnotations();
          }

          java.lang.Package
          java.lang.Class
          java.lang.reflect.Construtor
          java.lang.reflect.Field
          java.lang.reflect.Method
          均實現了該接口,所以我們可以通過反射獲取到 Class、Construtor、Field、Mehtod等,然后再通過上述接口方法,獲得作用在這些元素上的注解。
          下面是RequestParam注解的使用,為便于演示,略作修改,見org.springframework.web.bind.annotation.support.HandlerMethodInvoker源碼

          Method handlerMethod = *****;
          Annotation[] paramAnns 
          = handlerMethod.getParameterAnnotations();

          String paramName 
          = null;
          boolean required = false;
          String defaultValue 
          = null;

          for (Annotation paramAnn : paramAnns) {
              
          if (RequestParam.class.isInstance(paramAnn)) {
                  RequestParam requestParam 
          = (RequestParam) paramAnn;
                  paramName 
          = requestParam.value();
                  required 
          = requestParam.required();
                  defaultValue 
          = parseDefaultValueAttribute(requestParam.defaultValue());
                  annotationsFound
          ++;
              }
                 
          // *******其他處理*******************             
          }


          4、常見注解的說明及使用

          @Override :@Target(ElementType.METHOD)   @Retention(RetentionPolicy.SOURCE)  說明方法是對父類方法的覆蓋,用于編譯器編譯時進行檢查
          @Deprecated: @Documented  @Retention(RetentionPolicy.RUNTIME)   用于建議不要使用某元素
          @SuppressWarnings:@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) 
              說明對被批注的代碼元 素內部的某些警告保持靜默
          posted @ 2011-08-22 18:33 liucs 閱讀(2038) | 評論 (0)編輯 收藏
          摘錄 http://www.infoq.com/cn/articles/why-recommend-nodejs 部分內容

          JavaScript是一種函數式編程語言,函數編程語言最重要的數學基礎是λ演算(lambda calculus) -- 即函數對象可以作為其他函數對象的輸入(參數)和輸出(返回值)。
          函數運行時需要訪問函數定義時的上下文數據。并且javascript支持匿名函數。
          JavaScript中一個函數也是一個對象。一個函數實例fn除了函數體的定義之外,我們仍然可以在這個函數對象實例之本身擴展其他屬性,如fn.a=1;
          在每個JavaScript函數運行時,都有一個運行時內部對象稱為Execution Context,它包含如下Variable Object(VO,變量對象), Scope Chain(作用域鏈)和"this" Value三部分。如圖:


          只要能明確的區分函數定義和函數運行兩個時機,那么閉包就是讓函數在運行時能夠訪問到函數定義時的所處作用域內的所有變量,或者說函數定義時能訪問到什么變量,那么在函數運行時通過相同的變量名一樣能訪問到。
          posted @ 2011-08-15 09:44 liucs 閱讀(330) | 評論 (0)編輯 收藏
           http://www.ibm.com/developerworks/cn/java/j-jtp06197.html  一文筆記

          在java中,為了提高性能,線程一般把變量從內存中備份一個副本到寄存器。volatile 關鍵字意思是易失性,明確表示
          一個變量是會被多線程訪問的,每個線程在每次讀取都要從內存讀取原始副本的值,而不是緩存在寄存器中的值。每次修改
          都是把值寫回到內存中。

          Java語言包含兩種內在的同步機制:同步塊(或方法)和 volatile 變量。

          synchronized鎖提供了兩種主要特性:互斥(mutual exclusion)可見性(visibility)。互斥即一次只允許一個線程持有某個特定的鎖,因此可使用該特性實現對共享數據的協調訪問協議,這樣,一次就只有一個線程能夠使用該共享數據。可見性必須確保釋放鎖之前對共享數據做出的更改對于隨后獲得該鎖的另一個線程是可見的。 否則,線程看到的共享變量可能是修改前的值或不一致的值,引發嚴重問題。

          volatile能夠實現上述可見性,因為線程每次都是讀取原始版本的值,前一個線程的修改對后續線程來說是可見的。但volatile不能確保互斥。

          volatile適用的原則:
          • 對變量的寫操作不依賴于當前值。
          • 該變量沒有包含在具有其他變量的不變式中。
          所以volatile不能用作計數器,因為計數器的自增是一個讀-增-寫的過程,不是原子操作,在volatile不確保互斥的情況下,結果不準確。
          不變式的意思是一個需要不變的規律,如起始要小于等于結束。上述2點簡單來說:即變量真正獨立于其他變量和自己以前的值 , 在這些
          情況下可以使用 volatile 代替 synchronized 來簡化代碼。

          volatile由于不阻塞線程,在性能一般比synchronized表現更好。

          適用volatile的幾個場景:
          1、狀態標志  比如標示服務啟動或停止。
          2、獨立觀察  定期 “發布” 觀察結果供程序內部使用,
          3、結合使用 volatile 和 synchronized 實現 “開銷較低的讀-寫鎖”
          @ThreadSafe
          public class CheesyCounter {
          private volatile int value;
          // 使用volatile實現可見性,開銷低
          public int getValue() { return value; }
          // 使用synchronized實現互斥
          public synchronized int increment() {
          return value++;
          }
          }



          posted @ 2011-04-08 16:28 liucs 閱讀(376) | 評論 (0)編輯 收藏
          本文是閱讀《高性能網站建設指南》一書的筆記。該書作者是Yahoo!的Steve Souders ,總結了yahoo!在web前端優化的最佳實踐。

          Web前端性能黃金法則:只有10%-20%的最終用戶響應時間花在下載html文檔上。其余時間花在了下載頁面中所有的組件上。
          頁面組件包括:圖片,javascript,css,flash等內容

          Http請求響應
          GET /home/**.js
          HTTP 1.1
          Host: www.taobao.com
          User-Agent: Mozilla/**
          Accept-Encoding:gzip,deflate  ----》支持壓縮
          If-Modified-since:web,22 Feb**   -----》判斷是否采用瀏覽器緩存
          Expires:web****  -----》明確聲明失效時間,避免If-Modified-since條件請求的至少一次與服務器的交互
          Connection: keep-alive ----》使用長連接
          --------------------------------------------------------------------------------------------------------------------
          HTTP 1.1 304 Not Modified ----》沒修改
          Content-Type: application/x-javascript
          Last-Modified : web,22**
          Content-Encoding:gzip

          更詳細的見http規范: http://www.w3.org/Protocols/rfc2616/rfc2616.html

          1、減少HTTP請求
          • 使用圖片地圖 一個圖片上面關聯多個URL,由點擊的位置決定目標URL,目的在于建設圖片數量
          • CSS Sprites 講多個圖片合并成一幅圖片,圖片地圖中的圖片要連續,Css Sprites不需要
          • 內聯圖片
          • 合并腳本和樣式表 網站首頁平均應該使用6、7個腳本和1、2個樣式表
          2、使用外部JavaScript和CSS

             單純來說,內聯比外聯更快一些。

             對于用戶訪問很少的頁面,比如注冊等,建議內聯。

             對于用戶訪問較多的頁面,比如list或者商品詳情頁面等,建議外聯,瀏覽器可以使用緩存的組件。

             對于重用性較高的組件,使用外聯

          3、使用內容發布網絡
            
          CDN(Content Delivery Network)內容分發網絡,讓用戶就近訪問頁面靜態組件
          4、減少DNS查找
              通常瀏覽器查詢一個給定的主機名的ip需要花費20-120毫秒。建議將頁面組件放在至少2個,但不超過4個的主機名下。
          5、添加Expires或者Cache-Control頭 
            
          Expires和Cache-Control頭都用于瀏覽器可以使用本地緩存直至制定的時間,web服務器如apache,lighttpd,nginx等都有相應模塊可配置
          6、精簡JavaScript
            精簡代碼,將所有不必要的注釋和空白換行等移除。可以使用 JSMin(http://crockford.com/javascript/jsmin)進行精簡。
          7、壓縮組件 
            
          Accept-Encoding頭,一般只壓縮腳本和樣式表,圖片不需要,因為圖片通常都是壓縮過的。Apache 2.x使用mod_deflate模塊gzip壓縮
          8、避免重定向
            
          重定向使得html文檔到達前,頁面不會呈現任何內容。所以要減少重定向
          9、將樣式表放在頂部
            
          樣式表放在底部,瀏覽器為了在樣式表變化時不需要重繪頁面會阻止內容自頂向下逐步呈現。將CSS放在頂部,有利于瀏覽器從上向下顯示頁面
             推薦使用<link rel="stylesheet" href="common.css">方式,而不是import方式,因為import方式會導致組件下載的無序性,破壞了放在頂部的初衷。
          10、移除重復腳本
            
          由于團隊成員的長期維護,會遺留一定的重復腳本,需要定期清理
          11、將腳本放在底部  
           
          瀏覽器遵從http規范并行的從每個主機名并行下載兩個組件。這樣可以有效提高下載的效率。但瀏覽器在下載腳本時時禁用并行下載的,因為腳本有可能修改頁面內容。瀏覽器會阻塞確保頁面恰當的布局。
          12、配置ETag
          13、避免CSS表達式  
            
          CSS表達式是實現的效果可以通過其他手段實現,并且風險更小。
          14、使Ajax可緩存

             Ajax只是實現了異步,避免頁面的重新加載,但是不意味著即時。所有一個用戶在操作后仍然要等待才能看到結果。一些緩存的原則也可以適用于ajax.
          GET 方式可以更快響應,但是可能會有被瀏覽器緩存的問題,一般都需要加個隨機數來避免,POST 方式則不會。

          15、Cookie
          減少cookie中的信息,避免不重要的信息放在cookie中;對于圖片或者靜態服務器,使用cookie無關的域名,避免cookie的傳輸。
          posted @ 2011-04-08 10:59 liucs 閱讀(300) | 評論 (0)編輯 收藏
          java dynamic proxy

          核心java.lang.reflect.Proxy類

          // 根據給定接口和ClassLoader獲取Class對象
          // 使用Class.forName動態加載Class
          public static Class<?> getProxyClass(ClassLoader loader, Class<?> interfaces);
          // 創建代理對象
          // 通過反射的Constructor創建代理對象
          public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h);
          // 判斷是否是代理Class
          public static boolean isProxyClass(Class<?> cl);
          // 獲得代理對象的InvocationHandler
          public static InvocationHandler getInvocationHandler(Object proxy)

          java.lang.reflect.InvocationHandler接口

          // 反射調用代理類方法
          public Object invoke(Object proxy, Method method, Object[] args)
              
          throws Throwable;

          org.springframework.aop.framework.JdkDynamicAopProxy
          springframeworkAOP特性實現的基礎之一,通過動態代理實現
            1 package org.springframework.aop.framework;
            2 
            3 final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
            4 
            5     /** 代理的配置信息 */
            6     private final AdvisedSupport advised;
            7 
            8     public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
            9         Assert.notNull(config, "AdvisedSupport must not be null");
           10         if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
           11             throw new AopConfigException("No advisors and no TargetSource specified");
           12         }
           13         this.advised = config;
           14     }
           15 
           16 
           17     public Object getProxy() {
           18         return getProxy(ClassUtils.getDefaultClassLoader());
           19     }
           20     
           21     // 獲取代理對象
           22     public Object getProxy(ClassLoader classLoader) {
           23         if (logger.isDebugEnabled()) {
           24             logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());
           25         }
           26         Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);
           27         findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
           28         // 使用了Proxy動態代理創建代理對象
           29         return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
           30     }
           31 
           32 
           33     // 回調代理對象
           34     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
           35         MethodInvocation invocation;
           36         Object oldProxy = null;
           37         boolean setProxyContext = false;
           38 
           39         TargetSource targetSource = this.advised.targetSource;
           40         Class targetClass = null;
           41         Object target = null;
           42 
           43         try {
           44             if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
           45                 // The target does not implement the equals(Object) method itself.
           46                 return equals(args[0]);
           47             }
           48             if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
           49                 // The target does not implement the hashCode() method itself.
           50                 return hashCode();
           51             }
           52             if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
           53                     method.getDeclaringClass().isAssignableFrom(Advised.class)) {
           54                 // Service invocations on ProxyConfig with the proxy config
           55                 return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
           56             }
           57 
           58             Object retVal;
           59 
           60             if (this.advised.exposeProxy) {
           61                 // Make invocation available if necessary.
           62                 oldProxy = AopContext.setCurrentProxy(proxy);
           63                 setProxyContext = true;
           64             }
           65 
           66             // May be null. Get as late as possible to minimize the time we "own" the target,
           67             // in case it comes from a pool.
           68             target = targetSource.getTarget();
           69             if (target != null) {
           70                 targetClass = target.getClass();
           71             }
           72 
           73             // Get the interception chain for this method.
           74             List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
           75 
           76             if (chain.isEmpty()) {
           77                 // 如果攔截鏈是空的,直接通過反射調用target對象的方法
           78                 // method.invoke(target, args);
           79                 retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);
           80             }else {
           81                 // 如果攔截鏈不為空,包裝一個反射方法調用
           82                 // 先調用織入的攔截器,最后仍然是反射調用target對象的方法
           83                 invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
           84                 // Proceed to the joinpoint through the interceptor chain.
           85                 retVal = invocation.proceed();
           86             }
           87 
           88             // Massage return value if necessary.
           89             if (retVal != null && retVal == target && method.getReturnType().isInstance(proxy) &&
           90                     !RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
           91                 // Special case: it returned "this" and the return type of the method
           92                 // is type-compatible. Note that we can't help if the target sets
           93                 // a reference to itself in another returned object.
           94                 retVal = proxy;
           95             }
           96             return retVal;
           97         }
           98         finally {
           99             if (target != null && !targetSource.isStatic()) {
          100                 // Must have come from TargetSource.
          101                 targetSource.releaseTarget(target);
          102             }
          103             if (setProxyContext) {
          104                 // Restore old proxy.
          105                 AopContext.setCurrentProxy(oldProxy);
          106             }
          107         }
          108     }
          109 }
          110 



          posted @ 2011-04-06 10:58 liucs 閱讀(1312) | 評論 (0)編輯 收藏
          低耦合、高內聚

          OOP設計原則主要提供了一個方向,使得我們的程序設計得更加合理,從而獲得更好的可擴展性、可維護性。主要包括以下幾個原則:

          1、OCP(Open-Closed Principle) 開放封閉原則。
          對擴展開放,對修改關閉。即在不修改原有程序源碼的情況下對其進行擴展。實現開閉原則的關鍵就在于“抽象”。 “作為系統設計的抽象層,要預見所有可能的擴展,從而使得在任何擴展情況下,系統的抽象底層不需修改;同時,由于可以從抽象底層導出一個或多個新的具體實 現,可以改變系統的行為,因此系統設計對擴展是開放的。 ” 這個原則是OOP的基石,其他原則主要來實現本原則。

          2、SRP (Simple Responsibility Pinciple)單一職責原則。
          一個類一般應該設計成只有一個職責,如果設計成具備很多職責,那么任何一個職責的改變都會引起這個類的修改,相關引用該類的代碼也可能受到影響。不同的職責或功能應該由不同的類來實現,這樣可以很好的控制變化帶來的影響粒度。

          3、DIP (Dependence Inversion Principle)依賴倒轉原則。
          抽象不應該依賴于實現細節,實現細節應該依賴于抽象;高層不應該依賴于底層,都應該依賴于抽象。針對接口編程: 應該用接口或者抽象類聲明變量、方法參數、方法返回類型等。

          4、LSP (Liskov Substitution Principle)里氏代換原則。
          子類型完全可以替換父類型,而不需要任何修改,并且獲得期望的結果。

          5、ISP (Interface Segregation Principle)接口隔離原則。
          客戶端不應該可以訪問不需要的方法,這些不需要的方法是一種有害的耦合性。
          所以應該設計多個專門接口而不是單個復雜的接口,客戶端僅依賴最小的接口類型。

          6、LoD (Law of Demeter)迪米特法則。
          即最少知識原則。一個對象應當對其他對象有盡可能少的了解。只和最直接的類交互,對第三方可以通過轉達交互,從而減少對象間的耦合性。

          7、CARP (Composite/Aggregate Reuse Principle)合成/聚合復用原則。
          多聚合、少繼承,實現復用性。聚合的復用是一種封閉性的復用,被復用者對復用者隱藏了自身細節,而繼承是一種開放性的復用,子類可以獲取父類型相關的細節,破壞了封閉性。
          posted @ 2011-03-31 14:07 liucs 閱讀(398) | 評論 (0)編輯 收藏
          Java Reflection 是一種內省機制,幫助程序在運行時對自身及軟件環境進行檢查,并根據檢查得到的程序結構,改變自身的部分行為。

          核心類為 java.lang.Class 類,抽象了程序的元數據,每一個類的元數據就是一個Class對象實例。這個Class實例是一個靜態實例,對應類的每一個實例都會關聯這個靜態實例。通過Class類可以查詢該類的方法、字段、接口、構造器等一系列信息。詳見下面。

          對象回去自身對應的Class實例是通過繼承自Object類的getClass()方法;
          對于基本類型,每一種也有一個名為class的靜態實例,如int.class double.class boolean.class;
          對于數組類型,也有Object[].class, 注意 int[][].class==int[].class


          判斷對象類型的接口:
          String getName() 獲得類全名
          Class getComponentType() 如果對象是數組,返回數據中元素的類類型
          boolean isArray()
          boolean isInterface()
          boolean isPrimitive()
          boolean isAnnotation()

          ###########################################################################################################
          接口
          java.lang.Class中定義的檢查接口的接口:
          Class[] getInterfaces()
          Class getSuperClass() 直系父類 ,對于Object、接口、void關鍵字、基本類型,返回null
          boolean isAssignableFrom(Class cls) 該類是參數的類型或參數的父類型
          boolean isInstance(Object obj) 該類是參數的實例或者參數的子類實例

          Class類和Object類存在比較糾結的關系
          Class.class.isIntance(Class.class) == true Class類的class實例是Class本身的實例
          Class.class.isInstance(Object.class) == true
          Object.class.isAssignableFrom(Class.class) == true
          Object.class.isIntance(Class.class) == true

          ###########################################################################################################
          java.lang.reflect部分類圖


          ###########################################################################################################

          java.lang.reflect.Constructor
          java.lang.Class中相關方法

          Constructor getConstructor(Class[] parameterTypes)
          Constructor getDeclaredConstructor(Class[]parameterTypes)
          Constructor[] getConstructors()
          Constructor[] getDeclaredConstructors()

          java.lang.reflect.Constructor
          Class getDeclaredClass()
          Class[] getExceptionTypes()
          int getModifiers()
          String getName()
          Class[] getParameterTypes()
          Object newInstance(Object[] initArgs) 創建實例

          對于數組,使用 java.lang.reflect.Array.newInstance(String.class,5)形式創建實例

          ###########################################################################################################

          java.lang.reflect.Method

          java.lang.Class類中定義了如下接口查詢一個類所具有的方法。
          Method getMethod(String name,Class[]parameterTypes)
          Method[] getMethods()
          上述2個接口查詢繼承獲得和自身聲明的方法
          Method getDeclaredMethod(String name,Class[]parameterTypes)
          Method[] getDeclaredMethods()
          上述2個接口查詢自身聲明的方法

          java.lang.reflect.Method類定義的方法
          Class getDeclaringClass() 聲明該方法的類實例
          Class[] getExceptionTypes() 方法的異常類型
          int getModifiers() 方法的可見性
          String getName() 方法名
          Class[] getParameterTypes() 方法參數類型
          Class getReturnType() 方法返回類型
          Object invoke(Object obj,Object[]args) 反射調用一個對象上面的該方法

          ###########################################################################################################

          java.lang.reflect.Field

          java.lang.Class類中關于Field的相關方法:
          Field getField(String name)
          Field[] getFields()
          Field getDeclaredField(String name)
          Field[] getDeclaredFields()

          java.lang.relect.Field中主要方法
          Class getType() 返回字段的Class
          Class getDeclaringClass() 返回什么該字段的Class
          String getName()
          int getModifiers()
          Object get(Object obj) 返回obj該字段的值
          boolean getBoolean(Object obj)
          void set(Object obj,Object value) 設置obj該字段的值
          void setBoolean(Object obj,boolean value)

          ###########################################################################################################

          java.lang.reflect.Modifier 字段或者方法的訪問性
          static boolean isPublic(int mod)
          static boolean isPrivate(int mod)

          共包括以下:
          public static native volatile protected transient
          abstract synchronized strictfp private final


          ###########################################################################################################
          動態加載
          Class cls = Class.forName(String className);
          Object obj 
          = cls.newInstance();

          動態加載機制使得可以避開編譯器類范圍的限制,常見場景是jdbc驅動。動態加載機制也是通過ClassLoader實現。
          通過動態加載機制的類名并不是一般意義的類名,而是:
          1、基本類型,首字母大寫,如 int -> I
          2、引用類型,L+全類名,如 Ljava.lang.String
          3、數組類型,[+***, 如[I,   [Ljava.lang.String  ,  [[I,  [[Ljava.lang.String

          注意:基本類型,不能通過Class.forName()加載,會拋出異常
          posted @ 2011-03-31 14:06 liucs 閱讀(333) | 評論 (0)編輯 收藏
          Java在方法參數傳遞時:

          1、對于基本類型,傳遞值
          2、對于對象類型,傳遞對象引用
          需要注意的是:對于上述兩種傳遞類型,在傳遞時都是拷貝傳遞,即值傳遞時拷貝出一個新值,引用
          傳遞時拷貝出一個新的拷貝。

          有時候也說Java只有值傳遞,意思是對于引用類型,傳遞引用的值。一個概念,不用糾纏。

          在內存中對象類型可以看做兩塊,一塊是對象的引用,一塊是數據區。引用塊里面保存了數據區的地址。
          看如下示例代碼:
           1 public class Test {
           2 
           3     public static void main(String[] args) {
           4         // 值傳遞
           5         int i = 1;
           6         addInt1(i);
           7         System.out.println(i);// 輸出1
           8         addInt2(i);
           9         System.out.println(i);// 輸出1
          10 
          11         // 引用傳遞實例1
          12         String str = "123";
          13         modifyStr1(str);
          14         System.out.println(str);// 輸出123
          15 
          16         // 引用傳遞實例2
          17         StringBuilder stringBuilder = new StringBuilder("123");
          18         modifyStringBuilder(stringBuilder);
          19         System.out.println(stringBuilder.toString());// 輸出123456
          20     }
          21 
          22     // 拷貝了新的值,原值不變
          23     public static void addInt1(int i) {
          24         i = 2;
          25     }
          26 
          27     // 拷貝了新的值,原值不變
          28     public static void addInt2(int i) {
          29         i++;
          30     }
          31 
          32     // 新的拷貝引用指向了一塊新數據區,原拷貝仍然指向原數據區
          33     public static void modifyStr1(String str) {
          34         str = "456";
          35     }
          36 
          37     // 新的拷貝引用仍然指向原數據區,但修改了原數據區的內容
          38     public static void modifyStringBuilder(StringBuilder str) {
          39         str.append("456");
          40     }
          41 
          42 }

          posted @ 2011-03-31 14:05 liucs 閱讀(308) | 評論 (0)編輯 收藏
          僅列出標題  
          主站蜘蛛池模板: 资讯 | 霍邱县| 桂平市| 墨江| 道孚县| 上蔡县| 兖州市| 丰县| 正安县| 体育| 延吉市| 安化县| 黔西| 东丽区| 锡林浩特市| 吉安县| 新竹县| 大丰市| 正镶白旗| 太仆寺旗| 章丘市| 江源县| 玉环县| 辽阳县| 突泉县| 搜索| 大埔县| 奉贤区| 华阴市| 河南省| 阿尔山市| 庄浪县| 诏安县| 巴青县| 山阴县| 五指山市| 曲靖市| 文化| 扎鲁特旗| 高唐县| 蒲江县|