本文个人博客地址:https://abeille.top/blog/detail/AT815XG44
代理模式:其主要作用有两个,一个是保护目标对象,另外一个是增强目标对象;代理模式属于结构型模式;按其类型分为::静态代理::和::动态代理::;
代理的外部功能和实际对象一般一致,用户和代理打交道,不直接接触实际对象。虽然外部功能和实际对象一样,但是代理有它存在的价值:
代理模式中的三种角色:
创建顶层接口Person(抽象主题角色):
public interface Person {
public void findLove();
}
实现Son类(具体主题角色):
public class Son implements Person {
@Override
public void findLove () {
System.out.println(“相亲找对象”);
}
}
实现Father类(代理主题角色):
public class Father implements Person {
private Son son;
public Father (Son son) {
this.son = son;
}
@Override
public void findLove () {
System.out.println(“父亲托人介绍”);
this.son.finsLove();
System.out.println(“相亲成功”);
}
}
调用示例;
public class ProxyExample {
public static void main(String[] args) {
Person person = new Father(new Son());
person.findLove();
}
}
代码说明:例子中Son、Father都实现了Person这个接口,在Father类内部有一个Son的成员变量,指向实际的Son对象,在构造方法中被初始化,对于findLove()方法的调用,转发给了实际的对象;
public class SimpleInvocationHandler implements InvocationHandler {
private Object obj;
// obj 表示被代理对象
public SimpleInvocationHandler (Object obj) {
this.obj = obj;
}
/** proxy表示本身,method表示正在被调用的接口方法,args表示方法的参数 */
@Override
public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(“entering” + method.getName());
Object result = method.invoke(obj, args);
System.out.println(“leaving” + method.getName());
return result;
}
}
示例调用:
public class DynamicProxyExample {
public static void main (String[] args) {
Father father = new Father();
Class<? extends Person> pc = father.getClass();
// newProcyInstance 的返回类型可以强制转换为interfaces中的某个接口的类型,但是不能转换为某个类的类型,
// 例如:该方法中,只能强转为Person而不能转换为Father
Person person = (Person)Proxy.newProxyInstance(pc.getClassLoader(), pc.getInterfaces(), new SimpleInvocationHandler(father));
person.findLove();
}
}
动态代理的优点:
使用动态代理可以编写通用的代理逻辑,用于各种类型的被代理对象,而不需要为没被代理的类型都创建一个静态代理类;
JDK动态代理的局限性:
只能为接口创建代理,返回的代理对象也只能转换成接口类型;
public class Father {
public void say(){
System.out.println(“morining”);
}
}
创建代理执行类:
public class SimpleInterceptor implements MethodInterceptor {
@Override
public Object intercept (Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println(“entering” + method.getName());
// 这里需要调用invokeSuper()
Object result = method.invokeSuper(obj, args);
System.out.println(“leaving” + method.getName());
return result;
}
}
调用示例:
public class CglibExample {
public static <T> T getProxy () {
Enhancer enhancer = new Enhancer();
enhancer.setSuperClass(Father.class);
enhancer.setCallback(new SimpleInterceptor());
return (T) enhancer.create();
}
public static void main (String[] args) {
Father proxy = getProxy();
proxy.say();
}
}
JDK动态代理与CGLIB动态代理对比:
JDK动态代理面向的是一组接口,它为这些接口动态的创建一个实现类,接口的具体实现逻辑是通过自定义的InvocationHandler实现的,这个实现是自定义的,也就是说,其背后都不一定有真正被代理的对象,可能有多个实际对象,根据情况动态选择;
从代理的角度看,JDK动态代理代理的是对象,需要现有一个实际对象,自定义的InvocationHandler引用该对象,然后创建一个代理类和代理对象,客户端访问的是代理对象,代理对象再调用实际的对象方法;
JDK动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvocationHandler来处理;
CGLIB动态代理面向的是一个具体的类,它动态创建一个新类,继承被代理对象的类,重写其方法;
从代理的角度看,CGLIB动态代理代理的是类,创建的对象只有一个;
CGLIB动态代理是利用asm开源包,对被代理对象类的class文件加载进来,通过修改其字节码生成子类来处理