第十三章:代理模式
一、基本介绍
1)提供一个目标对象的代理,可以通过这个代理对象间接访问目标对象,而且还可以在目标对象已有的功能上扩展功能
2)被代理对象可以是远程对象、创建开销大的对象或需要安全控制的对象
3)代理模式主要分为:静态代理和动态代理,动态代理包括 JDK 代理、Cglib 代理
二、静态代理
静态代理很简单,要求代理对象的目标对象要有共同的父类,即它们是兄弟关系
静态代理类图:
具体实现代码:
父类接口
public interface AbstractTeacher {
void teach();
}
目标对象
public class OfficalTeacher implements AbstractTeacher{
@Override
public void teach() {
System.out.println("正在上课。。。");
}
}
代理对象
public class ProxyTeacher implements AbstractTeacher {
private AbstractTeacher teacher;
public ProxyTeacher() {
teacher = new OfficalTeacher();
}
@Override
public void teach() {
System.out.println("代理老师");
teacher.teach();
}
}
测试对象
public class ProxyTest {
public static void main(String[] args) {
ProxyTeacher proxyTeacher = new ProxyTeacher();
proxyTeacher.teach();
}
}
优点 | 缺点 |
---|---|
在不修改目标对象功能的前提下,就能通过代理对象对目标功能扩展 | 因为是静态代理,所以会客观存在代理类 |
一旦接口增加方法,目标对象和代理对象都要扩展 |
三、动态代理
动态代理对象是动态在内存中构建的
1. JDK 代理
1)代理对象不需要实现接口,但是目标对象必须实现接口
2)代理类所在包:java.lang.reflect.Proxy
jdk 代理实例:
代理工厂类
public class ProxyFactory {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
public Object getProxyInstance() {
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), (proxy, method, args) -> { // (代理对象,目标对象的方法,传入参数)
System.out.println("jdk 代理");
Object returnVal = method.invoke(target, args);
return returnVal;
});
}
}
测试类
public class JDKProxyTest {
public static void main(String[] args) {
OfficalTeacher target = new OfficalTeacher();
ProxyFactory factory = new ProxyFactory();
factory.setTarget(target);
// jdk 代理类是目标类的兄弟,所以不能强转成目标类哦
AbstractTeacher teacher = (AbstractTeacher) factory.getProxyInstance();
teacher.teach();
}
}
2. Cglib 代理
1)不需要目标对象实现任何接口(这是魔法吗!)
2)Cglib 代理又叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展
3)Cglib 是一个强大的高性能代码生成包,它可以在运行期扩展 java 类与实现 java 接口、(+_+)?
4)Cglib 包的底层是通过字节码处理框架 ASM 来转换字节码并生成新的类
Cglib 代理实例:
引入相关 jar 包
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.2</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-commons</artifactId>
<version>9.2</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-tree</artifactId>
<version>9.2</version>
</dependency>
注意目标类不能为 final,因为我们的代理类要继承的嘛。
目标对象的方法如果为 final/static,那么就不会被拦截。
代理工厂类
public class CgProxyFactory implements MethodInterceptor{
private Object target;
public void setTargat(Object targat) {
this.target = targat;
}
public Object getProxyInstance() {
// 1.创建一个工具类
Enhancer enhancer = new Enhancer();
// 2.设置父类
enhancer.setSuperclass(target.getClass());
// 3.设置回调
enhancer.setCallback(this);
// 4.创建子类对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib 代理");
Object returnVal = method.invoke(target, objects);
return returnVal;
}
}
测试类
public class CglibProxyTest {
public static void main(String[] args) {
OfficalTeacher target = new OfficalTeacher();
CgProxyFactory factory = new CgProxyFactory();
factory.setTargat(target);
// Cglib 代理类是目标类的儿子
OfficalTeacher teacher = (OfficalTeacher) factory.getProxyInstance();
teacher.teach();
}
}
可以通过这个案例,再次感受到了工厂模式的必要!