代理模式
代理模式在 Java 开发中是⼀种⽐较常⻅的设计模式。设计⽬的旨在为服务类与客户类之间插⼊其他
功能,插⼊的功能对于调⽤者是透明的,起到伪装控制的作⽤。如租房的例⼦:房客、中介、房东。对
应于代理模式中即:客户类、代理类 、委托类(被代理类)。
为某⼀个对象(委托类)提供⼀个代理(代理类),⽤来控制对这个对象的访问。委托类和代理类有
⼀个共同的⽗类或⽗接⼝。代理类会对请求做预处理、过滤,将请求分配给指定对象。
代理的三要素
a、有共同的⾏为(结婚) - 接⼝
b、⽬标⻆⾊(新⼈) - 实现⾏为
c、代理⻆⾊(婚庆公司) - 实现⾏为 增强⽬标对象⾏为
静态代理
静态代理的特点
1、⽬标⻆⾊固定
2、在应⽤程序执⾏前就得到⽬标⻆⾊
3、代理对象会增强⽬标对象的⾏为
4、有可能存在多个代理 引起"类爆炸"(缺点)
动态代理
相⽐于静态代理,动态代理在创建代理对象上更加的灵活,动态代理类的字节码在程序运⾏时,由
Java反射机制动态产⽣。它会根据需要,通过反射机制在程序运⾏期,动态的为⽬标对象创建代理对
象,⽆需程序员⼿动编写它的源代码。动态代理不仅简化了编程⼯作,⽽且提⾼了软件系统的可扩展
性,因为反射机制可以⽣成任意类型的动态代理类。代理的⾏为可以代理多个⽅法,即满⾜⽣产需要的
同时⼜达到代码通⽤的⽬的。
动态代理的两种实现方式:
- JDK 动态代理
- CGLIB动态代理
动态代理的特点
-
⽬标对象不固定
-
在应⽤程序执⾏时动态创建⽬标对象
-
代理对象会增强⽬标对象的⾏为
JDK动态代理
注:JDK动态代理的⽬标对象必须有接⼝实现
获取代理对象
public class JdkProxy {
/*
获取代理对象
*/
public static Object getJdkProxy(Object object){
Class clazz = object.getClass();
//1、调⽤⽬标对象的⽅法(返回Object)
//2、增强⽬标对象的⾏为
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(object, args);
System.out.println("没有闪");
return invoke;
}
});
}
}
Java动态代理类中的invoke是怎么调⽤的?
在⽣成的动态代理类$Proxy0.class中,构造⽅法调⽤了⽗类Proxy.class的构造⽅法,给成员变
量invocationHandler赋值,$Proxy0.class的static模块中创建了被代理类的⽅法,调⽤相应⽅法时⽅法体中调⽤了⽗类中的成员变量InvocationHandler的invoke()⽅法。
CGLIB 动态代理
JDK的动态代理机制只能代理实现了接⼝的类,⽽不能实现接⼝的类就不能使⽤JDK的动态代理,
cglib是针对类来实现代理的,它的原理是对指定的⽬标类⽣成⼀个⼦类,并覆盖其中⽅法实现增强,但
因为采⽤的是继承,所以不能对final修饰的类进⾏代理。
添加依赖
在pom.xml⽂件中引⼊cglib的相关依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
创建代理对象
public class CglibProxy {
public static Object getProxy(Object obj){
// 通过Enhancer对象的create()⽅法可以⽣成⼀个类,⽤于⽣成代理对象
Enhancer enhancer = new Enhancer();
// 设置⽗类 (将⽬标类作为其⽗类)
enhancer.setSuperclass(obj.getClass());
// 设置拦截器 回调对象为本身对象
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object invoke = method.invoke(obj, objects);
System.out.println("没有闪");
return invoke;
}
});
// ⽣成⼀个代理类对象,并返回
return enhancer.create();
}
}
JDK代理与CGLIB代理的区别
- JDK动态代理实现接⼝,Cglib动态代理继承思想
- JDK动态代理(⽬标对象存在接⼝时)执⾏效率⾼于Ciglib
- 如果⽬标对象有接⼝实现,选择JDK代理,如果没有接⼝实现选择Cglib代理