Spring AOP JDK动态代理与CGLib动态代理区别

静态代理与动态代理

静态代理

  • 代理模式

    (1)代理模式是常用设计模式的一种,我们在软件设计时常用的代理一般是指静态代理,也就是在代码中显式指定的代理。

(2)静态代理由 业务实现类、业务代理类 两部分组成。业务实现类 负责实现主要的业务方法,业务代理类负责对调用的业务方法作拦截、过滤、预处理,主要是在方法中首先进行预处理动作,然后调用业务实现类的方法

  • 例子

        /**
     * 定义一个账户接口
     * @author Administrator
     */
    public interface Count {
        // 查询账户
        public void queryCount();  

        // 修改账户
        public void updateCount();  

    }
    /**
 * 委托类(包含业务逻辑)
 *
 * @author Administrator
 *
 */
public class CountImpl implements Count {  

    @Override
    public void queryCount() {
        System.out.println("查看账户...");  

    }  

    @Override
    public void updateCount() {
        System.out.println("修改账户...");  

    }
}
    public class CountProxy implements Count {
    private CountImpl countImpl;  //组合一个业务实现类对象来进行真正的业务方法的调用

    /**
     * 覆盖默认构造器
     *
     * @param countImpl
     */
    public CountProxy(CountImpl countImpl) {
        this.countImpl = countImpl;
    }  

    @Override
    public void queryCount() {
        System.out.println("查询账户的预处理——————");
        // 调用真正的查询账户方法
        countImpl.queryCount();
        System.out.println("查询账户之后————————");
    }  

    @Override
    public void updateCount() {
        System.out.println("修改账户之前的预处理——————");
        // 调用真正的修改账户操作
        countImpl.updateCount();
        System.out.println("修改账户之后——————————");
    }
}
  • 静态代理

    静态代理的缺点很明显:一个代理类只能对一个业务接口的实现类进行包装,如果有多个业务接口的话就要定义很多实现类和代理类才行。而且,如果代理类对业务方法的预处理、调用后操作都是一样的(比如:调用前输出提示、调用后自动关闭连接),则多个代理类就会有很多重复代码。这时我们可以定义这样一个代理类,它能代理所有实现类的方法调用:根据传进来的业务实现类和方法名进行具体调用。——那就是动态代理。


动态代理

  • JDK动态代理

    JDK动态代理设计到java.lang.relect包中的两个类:Proxy和InvocationHandler,InvocationHandler可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态将横切逻辑与业务逻辑编织到一起。Proxy利用InvocationHandler动态创建某一符合该接口的实例,生成目标类的代理对象。

    public class Monitor {

    public static void begin(){
        System.out.println("before");
    }

    public static void end(){
        System.out.println("after");
    }
}
    public interface CouponService {

    void getCoupon();
}
    public class CouponServiceImpl implements CouponService {

    public void getCoupon() {

        //Monitor.begin();
        try {
            System.out.println("业务代码");
        } catch (Exception e) {
            throw new RuntimeException();
        }
        //Monitor.end();
    }
}
    public class PerformanceHandler implements InvocationHandler {

    //被代理对象
    private Object target;

    public PerformanceHandler(Object target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        Monitor.begin();
        Object object = method.invoke(target, args);
        Monitor.end();
        return object;
    }
}
    public class Client {

    public static void main(String[] args) {

        //被代理对象
        CouponService target = new CouponServiceImpl();

        //让PerformanceHandler将监视横切逻辑编织到CouponService中
        PerformanceHandler performanceHandler = new PerformanceHandler(target);

        //通过Proxy的newProxyInstace()方法,为编织了业务逻辑与监控逻辑的handler创建一个符合CouponService接口的代理实现
        CouponService proxy = (CouponService) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),performanceHandler);

        proxy.getCoupon();
    }
}
  • Cglib 实现动态代理
    JDK创建代理只能为接口创建代理,实际开发中我们很难保证每个类都有其对应的接口,对于没有通过接口定义业务方法的类,JDK已经没法对其进行代理,这就出现了Cglib,通过字节码技术,为一个类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并织入横切逻辑。
    public class CglibProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class clazz) {
        //设置需要创建子类的类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        //通过字节码技术动态创建子类实例
        return enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before");
        //通过代理类调用父类中的方法
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("after");
        return result;
    }
}
    public class Client {

    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();

        //通过冬天生成子类的方式创建代理类
        CouponServiceImpl couponService = (CouponServiceImpl) proxy.getProxy(CouponServiceImpl.class);

        couponService.getCoupon();
    }
}
  • 总结

    Cglib所创建的动态代理,性能要比jdk创建的动态代理高。但对用Cglib创建代理的时间,JDK动态代理显然要快很多。对于无需单例的代理对象或实例池可以使用CGLib来创建代理(无需频繁创建),反之使用JDK动态代理。

上一篇:Spring AOP --JDK动态代理方式


下一篇:Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程