代理模式的再理解--动态代理

代理模式的理解 所述的代理属于静态代理。

静态代理是指程序编译期即确定代理类和被代理类的关系,而且一个静态代理类只能代理一个具体类。如果需要对实现了同一接口的不同具体类代理,静态代理需要为每一个具体类创建相应的代理类。

public interface ServiceInterface {
    void foo();
}
public class ServiceImpl implements ServiceInterface {

    @Override
    public void foo() {

    }

}
public class ServiceProxy implements ServiceInterface {

    private ServiceImpl serviceImpl;

    public ServiceProxy(ServiceImpl serviceImpl) {
        super();
        this.serviceImpl = serviceImpl;
    }

    @Override
    public void foo() {
        before();
        serviceImpl.foo();
        after();
    }

    private void before() {

    }

    private void after() {

    }
}

静态代理中代理对象直接包装了被代理对象。

与静态代理不同的是动态代理,动态代理是指代理类是在程序运行期间动态生成,并不存在代理类的字节码文件,代理类和被代理类的关系是在程序运行时确定的。

Java的动态代理是自JDK 1.3 开始通过java.lang.reflect类库中java.lang.reflect.Proxy类的静态方法Proxy.newInstanceProxy实现的。

// 方法 1: 该方法用于获取指定代理对象所关联的调用处理器
static InvocationHandler getInvocationHandler(Object proxy) 

// 方法 2:该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象
static Class getProxyClass(ClassLoader loader, Class[] interfaces) 

// 方法 3:该方法用于判断指定类对象是否是一个动态代理类
static boolean isProxyClass(Class cl) 

// 方法 4:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

若需要对代理类的业务逻辑前后增加一些功能性的行为,称为代理行为。

JDK动态代理需要创建一个实现java.lang.reflect.InvocationHandler接口的类,并在该类中定义代理行为。

// 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象
// 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行
Object invoke(Object proxy, Method method, Object[] args)

通过实现InvocationHandler接口创建自己的调用处理器

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ServiceInvocationHandler implements InvocationHandler {

    private Object target;

    public ServiceInvocationHandler(Object target) {
        super();
        this.target = target;
    }

    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), this.target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(target, args);
        after();
        return result;
    }

    private void before() {

    }

    private void after() {

    }
}

JDK 动态代理是通过反射实现的,而且因为都必须通过Proxy来创建,Proxy是所有的动态生成的类的父类,Java的继承机制注定了这些动态代理类们无法实现对class的动态代理,Java不支持多继承。仅仅只支持接口的动态代理。

cglib 动态代理不是通过反射实现的,cglib是通过ASM字节码编辑框架了对字节码文件进行编辑

JDK动态代理与cglib对比
字节码创建方式:JDK动态代理通过JVM实现代理类字节码的创建,cglib通过ASM创建字节码
对被代理对象的要求:JDK动态代理要求被代理对象实现接口,cglib要求被代理对象未被final修饰
代理对象创建速度:JDK动态代理创建代理对象速度比cglib快
代理对象执行速度:JDK动态代理代理对象执行速度比cglib快

动态代理的应用

AOP(Aspect-OrientedProgramming,面向切面编程),AOP包括切面(aspect)、通知(advice)、连接点(joinpoint),实现方式就是通过对目标对象的代理在连接点前后加入通知,完成统一的切面操作。

实现AOP的技术,主要分为两大类:

一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;

二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。

Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,具体使用哪种方式生成由AopProxyFactory根据AdvisedSupport对象的配置来决定。

默认的策略是如果目标类是接口,则使用JDK动态代理技术,如果目标对象没有实现接口,则默认会采用CGLIB代理。

如果目标对象实现了接口,可以强制使用CGLIB实现代理(添加CGLIB库,并在spring配置中加入<aop:aspectj-autoproxy proxy-target-class="true"/>)。

阅读更多

没有更多推荐了,返回首页