在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。
一、静态代理
静态代理的代理类每次都需要手动创建。
代理类和真实类都需要实现接口。
接口类
/**
* <p>
*抽象主题角色
* </p>
*
* @since 2022/3/21 17:19
*/
public interface TVCompany {
TV produceTV();
String print();
}
真实类
/**
* <p>
* 具体主题角色
* </p>
*
* @since 2022/3/21 17:20
*/
public class TVFactory implements TVCompany {
@Override
public TV produceTV() {
System.out.println("tvfactory prduce TV");
return new TV("小米", "济南");
}
@Override
public String print() {
System.out.println("print TV");
return "print TV";
}
}
代理类
/**
* <p>
*代理主题角色 静态代理
* </p>
*
* @since 2022/3/21 17:21
*/
public class TVProxy implements TVCompany {
private TVCompany tvCompany;
@Override
public TV produceTV() {
System.out.println("tvproxy prduce");
if (ObjectUtil.isNull(tvCompany)) {
tvCompany = new TVFactory();
}
return tvCompany.produceTV();
}
@Override
public String print() {
return "print TV";
}
}
测试类
//静态代理
TVProxy tvProxy = new TVProxy();
TV tv = tvProxy.produceTV();
System.out.println(tv.toString());
二、动态代理
从静态代理的代码中可以发现,静态代理的缺点显而易见,那就是当真实类的方法越来越多的时候,这样构建的代理类的代码量是非常大的,所以就引进动态代理.
动态代理允许使用一种方法的单个类(代理类)为具有任意数量方法的任意类(真实类)的多个方法调用提供服务,看到这句话,可以容易的联想到动态代理的实现与反射密不可分。
JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为 java 语言的反射机制。
1.jdk动态代理
jdk动态代理工厂
/**
* <p>
* 代理主题角色 jdk动态代理
* </p>
*
* @since 2022/3/21 17:26
*/
public class TVProxyFactory {
private Object target;
public TVProxyFactory(Object o) {
this.target = o;
}
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(), (proxy, method, args) -> {
System.out.println("tv proxy find factory for tv");
Object invoke = method.invoke(target, args);
return invoke;
});
}
}
测试代码
//jdk 动态代理
TVFactory tvCompany = new TVFactory();
TVCompany tvCompany1 = (TVCompany) new TVProxyFactory(tvCompany).getProxy();
System.out.println(tvCompany1.produceTV());
System.out.println(tvCompany1.print());
1.静态代理中,代理类和真实类实现的是同一个接口,重写同样的方法;jdk动态代理中,代理类和真实类关系不大,代理类实现无侵入式的代码扩展。
2.静态代理中当接口中方法增加的时候,在代理类代码量也会增加,显然是不妥的;jdk动态代理解决了这个问题,当业务增加,代理类的代码不会增加。
3.jdk动态代理实现的是jdk自带InvocationHandler接口,实现了这个接口的类也叫拦截器类,也叫代理类。
2.cglib动态代理
从上面可以看出,jdk动态代理的前提条件是,要有接口存在,那还有许多场景是没有接口的,这个时候就需要cglib动态代理了,CGLIB(Code Generation Library)是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理。
cgli代理类
/**
* <p>
* 代理主题角色 CGLIB动态代理
* </p>
*
* @since 2022/3/21 17:37
*/
public class TVProxyCglib implements MethodInterceptor {
public Object getProxyInstance(Class c) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(c);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("tvproxycglib enhancement");
Object object = methodProxy.invokeSuper(o, objects);
return object;
}
}
测试代码
// cglib 动态代理
TVFactory tvFactoryS = (TVFactory) new TVProxyCglib().getProxyInstance(TVFactory.class);
TVFactoryB tvFactoryB = (TVFactoryB) new TVProxyCglib().getProxyInstance(TVFactoryB.class);
System.out.println(tvFactoryS.produceTV());
System.out.println(tvFactoryS.print());
System.out.println(tvFactoryB.produceTV());
System.out.println(tvFactoryB.print());
glib动态代理和jdk动态代理的区别显而易见,但是实现逻辑差不多,cglib代理类是通过实现MethodInterceptor,重写intercept方法,通过生成被代理类的子类来达到代理增强代码的目的;而Jdk代理是通过实现InvocationHandler,重写invoke方法,通过生成接口的代理类来达到代码增强的目的,所以jdk动态代理的实现需要接口,cglib则不需要
文章参考出处:https://blog.csdn.net/weixin_43953283/article/details/125783249