1、介绍
定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
在上述的过程中在编程的过程中我们可以定义为三类对象:
- Subject(抽象主题角色):定义代理类和真实主题的公共对外方法,也是代理类代理真实主题的方法。比如:广告、出售等。
- RealSubject(真实主题角色):真正实现业务逻辑的类。比如实现了广告、出售等方法的厂家(Vendor)。
- Proxy(代理主题角色):用来代理和封装真实主题。比如,同样实现了广告、出售等方法的超时(Shop)。
以上三个角色对应的类图如下:
Java代理及动态代理详解
2、静态代理
【例子】:父亲帮儿子相亲代码如下
//========(1)定义接口(人类都可以相亲)
public interface Person {
void findLove();
}
//=======(2)儿子相亲要求
public class Sun implements Person {
@Override
public void findLove() {
System.out.println("肤白");
System.out.println("貌美");
System.out.println("大长腿");
}
}
// ====== (3) 父亲代理
public class Father implements Person {
private Person person;
public Father(Person person){
this.person = person;
}
@Override
public void findLove() {
person.findLove();
}
}
//====== (4) 详情过程
public class StaticProxyTest {
public static void main(String[] args) {
// 先有一个儿子
Sun sun = new Sun();
// 再有一个儿子父亲
Father father = new Father(sun);
// 父亲相亲,实际是儿子相亲
father.findLove();
}
}
缺点:
(1)当需要代理多个类时,代理对象要实现与目标对象一致的接口。要么,只维护一个代理类来实现多个接口,但这样会导致代理类过于庞大。要么,新建多个代理类,但这样会产生过多的代理类。
(2)当接口需要增加、删除、修改方法时,目标对象与代理类都要同时修改,不易维护。
3、动态代理两种方式
(1) JDK自带动态代理
a、原理图:
动态代理原理图JDK动态代理,被代理的类必须是某接口实现类,代理过程是针对接口中的方法做反射生成。
通俗理解:动态生成代理类,调用目标实现接口去调用目标。目标类必须要实现接口
b、依赖两个核心
JDK动态代理主要涉及两个类:java.lang.reflect.Proxy
和java.lang.reflect.InvocationHandler
第一:调用处理接口InvocationsHandler
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
参数:obj一般是指代理类,method是被代理的方法,args为该方法的参数数组
第二:动态生成代理类
static Object newProxyInstance(ClassLoaderloader, Class[] interfaces, InvocationHandler h)
返回代理类的一个实例,返回后的代理类可以当作被代理类使用.
$Proxy.class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然,这个DynamicProxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
注:
// 设置该变量可以保存动态代理类,默认名称$Proxy0.class
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
c、整个代理过程
动态生成$Proxy文件
编译代理文件生成class
加载运行class文件中的方法
反射调用InvocationHandler 中的invoke方法
(2)CGLIB动态代理
通俗理解:动态生成代码去继承目标类。子类重写父类方法。目标类没有jdk那样实现接口的束缚。
CGLIB
:Code Generator Library是一个强大的、高性能的代码生成库。广泛应用于AOP框架。
【示例】
public class CGLIBMeipo implements MethodInterceptor {
public Object getInstance(Class<?> clazz){
//proxy 代理的工具类,生成要被代理的类的子类
Enhancer enhancer = new Enhancer();
// 设置生成类所属的父类
enhancer.setSuperclass(clazz);
// 设置回调方法,调用intercept
enhancer.setCallback(this);
return enhancer.create();
}
// 代理要走的方法
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = methodProxy.invokeSuper(o,objects);
after();
return obj;
}
public void before(){
System.out.println("CGLIB开始前增强逻辑");
}
public void after(){
System.out.println("CGLIB结束之后的增强逻辑");
}
// 测试
public static void main(String[] args) {
Target t = (Target) new CGLIBMeipo().getInstance(Target.class);
t.sayHello();
}
}
(3)jdk动态代理与cblib动态代理的区别
1、JDK动态代理是针对于接口代理,目标类必须实现了接口,产生的代理对象也会实现该接口。生成的代码简单,调用效率低(反射机制)。
2、CGLIB代理是采用继承,产生的代理对象继承于目标类,所以目标类和目标方法不能用final修饰。生成代码复杂,调用效率高(fastClass类直接调用),不能代理final 方法(final方法不能被重写)
参考:
https://blog.csdn.net/jiankunking/article/details/52143504
https://www.cnblogs.com/secbro/p/12537367.html
网友评论