静态代理与动态代理(JDK、CGLIB)

时间:2022-02-13 20:17:00

静态代理与动态代理(JDK、CGLIB)

问题引入

  • 什么是静态代理?
  • 什么是动态代理?
  • 静态代理和动态代理的区别是什么?
  • JDK动态代理和CGLIB动态代理的区别?

静态代理

主要是通过代码的业务来处理,在编译之前就已经处理好。

例子

先创建目标类

/** * Created on 2018/6/6 * 创建目标类接口 * @author wang.teng */
public interface BusiInterface {
    void execute();
}
/** * Created on 2018/6/6 * 目标类接口的实现 * @author wang.teng */
public class BusiInterfaceImpl implements BusiInterface {
    @Override
    public void execute() {
        System.out.println("处理业务");
    }
}

在创建代理类:


/** * Created on 2018/6/6 * 代理类,对目标的执行以及前置后置处理 * @author wang.teng */
public class Proxy implements BusiInterface{
    BusiInterface busiInterface;
    Proxy(BusiInterface busiInterface){
        this.busiInterface =busiInterface;
    }
    @Override
    public void execute() {
        before();
        busiInterface.execute();
        after();
    }

    public static void before() {
        System.out.println("前置处理");
    }
    public static void after() {
        System.out.println("后置处理");
    }

}
优点:

在不修改目标类的情况下可以对目标类进行拦截和拓展。

缺点:

代理类需要实现目标类接口,所以每个目标类都得相对有一个代理类,耦合性太强,目标类增加方法则代理类也得进行实现。

动态代理

JDK动态代理

动态代理是通过反射类拿到目标类的接口实现,进行拦截和拓展。

目标类和接口实现同上面的静态代理,主要不同的地方是代理类的实现,代理类主要是通过反射,拿到目标类的接口的实现,来获取目标类对象,再目标类执行方法的时候进行拦截。

/** * Created on 2018/6/6 * JDK动态代理类 * @author wang.teng */
public class DynamicProxy {
    public Object getProxyInstance(BusiInterface busiInterface){
      return Proxy.newProxyInstance(
              busiInterface.getClass().getClassLoader()
              busiInterface.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("前拦截...");
                        Object invoke = method.invoke(busiInterface, args);
                        System.out.println("后拦截...");
                        return invoke;
                    }
                });
    }
}
优点:

可以不用实现目标类的接口,直接通过反射拿到目标的方法进行拦截。

缺点:

目标类对象一定要实现接口

CGLIB代理

是通过字节码创建子类的方式,并在子类中采用方法拦截拦截父类所有的方法,进行切入。CGLIB可以代理没有接口的类。

例子:

先引入cglib包:

 compile group: 'cglib', name: 'cglib', version: '2.2.2'

目标类:

/** * Created on 2018/6/7 * 没有接口的对象类 * @author wang.teng */
public class Business {
    public void execuate(){
        System.out.println("do something !");
    }
}

代理类:


/** * Created on 2018/6/7 * * @author wang.teng */
public class CglibProxy implements MethodInterceptor {

    public Object getProxy(Class clazz){
        Enhancer enhancer = new Enhancer();
        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("前置交易");
        Object invokeSuper = methodProxy.invokeSuper(o, objects);
        System.out.println("后置交易");
        return invokeSuper;
    }
}
/** * Created on 2018/6/7 * * @author wang.teng */
public class Test {
    public static void main(String[] args) {
        CglibProxy proxy = new CglibProxy();
        Business business = (Business) proxy.getProxy(Business.class);
        business.execuate();
    }

}
优点:

可以代理类和接口,在执行效率比较高

缺点:

虽说在代理执行上效率比较高,但是在创建对象上,要使用字节码来进行创建对象,耗时会比JDK久很多。对于final修饰的方法是无法进行代理的。