静态代理与静态代理

1 代理模式及概念

    代理模式是给某个对象提供一个代理对象,并由代理对象控制对原始对象的引用。以下图:     代理模式java

    代理类和委托类有共同的父类,这样在任何使用原始对象(委托对象)的地方均可用代理对象替代。代理对象负责请求的预处理、过滤,将请求分派给原始对象,执行原始对象执行结束后的后续处理。spring

    所谓静态代理,是指在程序运行前,就已经存在代理类的字节码文件,代理类和原始类(委托类)的关系在运行前就已肯定。编程

    所谓动态代理,是指在程序运行期间,由JVM根据反射机制动态生成代理类的字节码文件,代理类和原始类(委托类)的关系是在运行时肯定的。ide

2 静态代理

2.1 编写代理模式实现静态代理

    编写代理模式,便可实现静态代理。但这样的话,有多少个委托类,就须要编写多少个代理类,即便代理逻辑是相同的。而以AspectJ为代理的静态代理,以及JDK动态代理、CGLib动态代理均可以解决这个问题,使得仅需在一个地方编写代理逻辑,这也是AOP思想和目的。工具

2.2 以AspectJ为表明的静态代理

    AspectJ是Java语言的一个AOP实现,主要包括两个部分:第一个部分定义了如何表达、定义AOP编程中的语法规范,经过这套语言规范,咱们能够方便地用 AOP 来解决Java语言中存在的交叉关注点问题;另外一个部分是工具部分,包括编译器、调试工具等。this

    Aspectj实现了独有的编译器,在编译时生成代理类文件。有关AspectJ的用法,参考http://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/代理

3 动态代理

    Spring AOP的核心就是动态代理。Spring动态代理有两种实现方式:JDK动态代理和CGLib动态代理,Spring会根据实际状况自行选择采用哪一种方式。调试

3.1 JDK动态代理

    JDK的动态代理,是基于接口的动态代理。Java API提供以下两个类帮助咱们实现动态代理:code

  • java.lang.reflect.Proxy,这是Java动态代理机制生成的全部动态代理类的父类,它提供静态方法来为一组接口动态地生成代理类及其对象。
  • java.lang.reflect.InvocationHandler,这是调用处理器接口,它自定义了一个invoke方法,用于实现代理逻辑、转发请求给对原始类对象。

如下是java动态代理编写示例:对象

/**
 * 主题接口
 */
public interface Subject {
    public void hello();
}
/**
 * 委托类或原始类
 */
public class DelegateSubject implements Subject {
    public void hello(){
        System.out.println("Hello, Word!");
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 调用处理器,负责实现代理逻辑、转发请求给委托对象
 */
public class SubjectInvocationHandler implements InvocationHandler {

    //代理类持有一个委托类的对象引用
    private Object delegate;

    public SubjectInvocationHandler(Object delegate) {
        this.delegate = delegate;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long stime = System.currentTimeMillis();
        System.out.println(">>begin: "+stime);

        //利用反射机制将请求转发给委托类处理,method.invoke返回Object对象做为方法执行结果。
        //由于委托类的相应方法程序没有返回值,因此这里不处理返回值
        method.invoke(delegate, args);
        long etime = System.currentTimeMillis();
        System.out.println(">>end: "+etime);

        System.out.println("执行任务耗时" + (etime - stime) + "毫秒。");
        return null;
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * 生成代理对象的工厂类
 */
public class DynProxyFactory {

    // 客户端调用此工厂方法得到代理对象,它并不知道返回的是代理类对象仍是委托类对象。
    public static Subject getInstance() {
        Subject delegate = new DelegateSubject();
        InvocationHandler handler = new SubjectInvocationHandler(delegate);
        Subject proxy = (Subject) Proxy.newProxyInstance(
                delegate.getClass().getClassLoader(),
                delegate.getClass().getInterfaces(),
                handler);
        return proxy;
    }
}
/**
 * 客户端
 */
public class Client {

    public static void main(String[] args) {
        Subject proxy = DynProxyFactory.getInstance();
        proxy.hello();
    }
}

3.2 CGLib动态代理

    尽管java API能够帮助咱们方便的实现动态代理,但因为生成的代理类已经继承了共同的父类(java.lang.reflect.Proxy),这就使得代理类没法再继承其它类,而只能实现接口。也就是说,JDK的动态代理机制只能代理实现了接口的类,而没有实现接口的类就不能代理。

    若是要实现对类的动态代理,那就要用CGLib,它的原理是对指定的目标类生成一个子类,并覆盖其中方法实现加强,但由于采用的是继承,因此不能对final修饰的类进行代理。

4 Spring AOP与AspectJ

    虽然Spring AOP采用了JDK动态代理和CGLib动态代理,但Spring 容许用AspectJ Annotation来定义方面(Aspect)、切入点(Pointcut)和加强处理(Advice), 而不须要使用AspectJ的编译器和织入器。

相关文章
相关标签/搜索