代理模式
定义
由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
解决什么问题
- 被访问对象应做控制
- 访问对象时添加一些额外功能
静态代理
- 代理类和被代理类实现相同的接口,代码重复,维护有难度
- 代理对象只服务于一种类型的对象,如果要服务多类型对象则要为每一种对象都进行代理,要代理的种类规模稍大时就显得力不从心了
动态代理
在程序运行期间根据需要动态创建代理类及其实例来完成具体的功能。
- JDK动态代理
- cglib动态代理
JDK动态代理
- 创建被代理的对象和类
- 创建InvocationHandler接口的实现类,在invoke方法中实现代理逻辑
- 通过Proxy类的静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h)创建一个代理对象
- 使用代理对象
关键代码示例
package com.jd.designpattern.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 代理Handler
*/
public class ProxyHandler implements InvocationHandler {
private Object object;
public ProxyHandler(Object object){
this.object = object;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("动态代理 - 执行前:" + method.getName());
method.invoke(object, args);
System.out.println("动态代理 - 执行后:" + method.getName());
return null;
}
}
其中的wirte()方法是将生成的代理类写入到本地,用idea打开后可查询生成的class到底是什么
package com.jd.test.proxy;
import com.jd.designpattern.proxy.ProxyHandler;
import com.jd.designpattern.proxy.ProxySubject;
import com.jd.designpattern.proxy.RealSubject;
import com.jd.designpattern.proxy.Subject;
import org.junit.Test;
import sun.misc.ProxyGenerator;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
/**
* 代理模式测试类
* @author jubingtao
* @date 2020-4-27
*/
public class ProxyTest {
@Test
public void testStaticProxy(){
//获取代理
Subject subject = new ProxySubject();
subject.request();
}
@Test
public void testDynamicProxy(){
Subject subject = new RealSubject();
InvocationHandler handler = new ProxyHandler(subject);
Subject proxySubject = (Subject) Proxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), handler);
proxySubject.request();
write();
}
private void write(){
String path = "D:/$Proxy0.class";
byte[] classFile = ProxyGenerator.generateProxyClass("$Proxy0",RealSubject.class.getInterfaces());
FileOutputStream out = null;
try {
out = new FileOutputStream(path);
out.write(classFile);
out.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {