代理模式是设计模式的一种。动态代理的特点就是编译阶段不生成代理类,运行时生成代理类。常见的动态代理有两种,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动态代理无法代理内部类,因为内部类的创建依赖外部类。如果非要代理内部类,有两种方法:
- 内部类加static,static修饰的内部类可以作为普通类来使用,不需要实例化外部类
- 在cglib创建类对象时传入外部类(对象声明类型是内部类)
-
动态代理应用场景
1、aop(Spring aop本质上就是通过动态代理实现的)
2、自定义第三方类库中的某些方法
参考博客:https://blog.csdn.net/flyfeifei66/article/details/81481222等,侵权即删