Java动态代理

代理模式是设计模式的一种。动态代理的特点就是编译阶段不生成代理类,运行时生成代理类。常见的动态代理有两种,JDK动态代理和CGLIB动态代理。JDK动态代理是基于反射机制实现的,cglib动态代理是基于asm实现的

jdk动态代理的实现

jdk动态代理主要需要用到InvocationHandler接口和Proxy类,都在java.lang.reflect包中

每一个动态代理类都需要实现InvocationHandler这个接口,并重写invoke(proxy, method,args[])方法,invoke方法中在逻辑代码的前后可以加上我们想要的其他逻辑

/**
 * JDK动态代理
 */
// 接口
public interface Factory {
    String sellProduct(String name);
}
// 实现类
public class Market implements Factory {
    @Override
    public String sellProduct(String name) {
        System.out.println("成本价1000");
        return "";
    }
}
// 代理类
public class ZhongJianShang implements InvocationHandler {
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 加强操作
        System.out.println("我是中间商,我要赚1000差价");
        // 调用原方法
        Object result = method.invoke(target, args);
        //加强操作
        System.out.println("便宜点,2000卖你");
        return result;
    }

    // 这个方法返回的是代理对象实例,返回代理类的方法不一定写在这里,可以写在一个工厂方法中
    public Object CreateProxyObject() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
}

// 测试
public class test {
    public static void main(String[] args) {
      Factory factory = new Market();
      ZhongJianShang zjs = new ZhongJianShang();
      zjs.setTarget(factory);
      Object obj = zjs.createProxyObject();
      factory = (Factory) obj;
      factory.sellProduct("手机");
    }
}
  • jdk动态代理的特点:
    JDK动态代理需要被代理类实现一个接口,所以不实现接口的类无法被动态代理,并且增强的方法只能是重写的接口中的方法(因为jdk动态代理是通过反射机制生成代理接口的匿名类,且该匿名类已经继承Proxy类,不能再继承其他类,实现交互获取方法只能通过接口,也因此增强的方法只能是接口中声明过的方法)

cglib动态代理的实现

cglib动态代理的类不需要实现任何接口,只需要实现MethodInterceptor接口并重写intercept方法即可

public class Market {
    public String sellProduct(String name) {
        System.out.println("成本价1000");
        return "";
    }
}

public class CglibZhongJianShang implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("我是中间商,我要赚差价1000");
		// 返回cglib动态代理创造的实体类
        Object obj = methodProxy.invokeSuper(o, objects);
        System.out.println("收您2000");
        return obj;
    }
}

public class test {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Market.class);
        enhancer.setCallback(new CglibZhongJianShang());

        Market market = (Market) enhancer.create();
        market.sellProduct("手机");
        // rap()可以被调用,没有被增强
    }
}
  • cglib动态代理的特点:
    cglib动态代理本质上是创建了被代理对象类的子类来实现动态代理,所以无法代理内部类(因为内部类的创建依赖于外部类),cglib不能代理final修饰的方法,但是方法可以被正常调用(final修饰的方法不能被继承)。

两者的区别

  • java动态代理实现了被代理对象的接口,利用反射机制生成代理接口的匿名类,cglib是创建了被代理对象的子类来实现动态代理。

  • java动态代理是直接写字节码,cglib使用asm框架写字节码。

  • cglib的性能比jdk动态代理好,但是cglib创建动态代理所话费的事件比较长,因此无需频繁创建代理对象的如线程池、单例用cglib比较好。

  • cglib动态代理无法代理内部类,因为内部类的创建依赖外部类。如果非要代理内部类,有两种方法:

  1. 内部类加static,static修饰的内部类可以作为普通类来使用,不需要实例化外部类
  2. 在cglib创建类对象时传入外部类(对象声明类型是内部类)
  • 动态代理应用场景

    1、aop(Spring aop本质上就是通过动态代理实现的)

    2、自定义第三方类库中的某些方法

参考博客:https://blog.csdn.net/flyfeifei66/article/details/81481222等,侵权即删

你可能感兴趣的:(java)