随笔 - 2  文章 - 2  trackbacks - 0
<2024年12月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

留言簿

随笔档案(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 阅读(6595) | 评论 (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 阅读(8497) | 评论 (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 阅读(2021) | 评论 (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 阅读(317) | 评论 (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 阅读(364) | 评论 (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 阅读(293) | 评论 (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 阅读(1301) | 评论 (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 阅读(386) | 评论 (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 阅读(321) | 评论 (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 阅读(296) | 评论 (0)编辑 收藏
仅列出标题