在说什么是代理模式之前我们先来看一个例子:
public interface Subject {
public void handleData();
}
public class MySubject implements Subject{
@Override
public void handleData(){
System.out.println("业务");
}
}
刚开始A公司还是小公司,业务也很简单,就只管实现业务就行了。但是过几年公司逐渐壮大,业务越来越复杂,这时候公司为了规范,要求每个业务都要打印日志上传服务。程序员小王觉得这个简单不就是在每个业务之前调用打印日志上传的功能嘛:
public class MySubject implements Subject{
@Override
public void handleData(){
System.out.println("打印日志上传");
System.out.println("业务");
}
}
这么一看好像问题解决了,但是貌似不符合我们开发的开闭原则啊,我们开闭原则不是说不修改源代码,在原来基础上进行扩展吗,这时候小王想到了自己最近刚学的代理模式
1.静态代理
1.原有的实现类保持不变
public interface Subject {
public void handleData();
}
public class MySubject implements Subject{
@Override
public void handleData(){
System.out.println("业务");
}
}
2.创建代理类:
public class Proxy implements Subject {
//持有被代理对象
Subject subject;
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void handleData() {
System.out.println("打印日志上传");
//调用被代理类的方法
subject.handleData();
}
}
小王创建了一个代理类,同样也实现了
Subject
接口,构造函数创建了被代理的对象。然后代理类的方法内部其实都是执行被代理对象的方法。我们只要在调用之前打印日志上传即可。
3.调用:
Proxy p =Proxy(new MySubject());
p.handleData();
输出结果:
2019-12-26 15:38:16.498 2989-2989/com.example.serializationapplication I/System.out: 打印日志上传
2019-12-26 15:38:16.498 2989-2989/com.example.serializationapplication I/System.out: 业务
小王很开心,发现自己解决了这个问题,但是过了一段时间后领导说每个业务功能执行前都要打印日志上传,但是小王发现整个系统很多业务,难不成要在代理类中的每个方法都调用一次打印日志?
public interface Subject {
public void handleData1();
public void handleData2();
public void handleData3();
}
public class MySubject implements Subject{
@Override
public void handleData1(){
System.out.println("业务1");
}
@Override
public void handleData2(){
System.out.println("业务3");
}
@Override
public void handleData3(){
System.out.println("业务3");
}
}
代理类:
public class Proxy implements Subject {
Subject subject;
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void handleData1() {
System.out.println("打印日志上传");
subject.handleData1();
}
@Override
public void handleData2() {
System.out.println("打印日志上传");
subject.handleData1();
}
@Override
public void handleData3() {
System.out.println("打印日志上传");
subject.handleData1();
}
}
小王觉得自己这么写得写到猴年马月去啊,并且项目还在不断扩大。于是他百度学到了动态代理。
1.动态代理
1.接口和实现类保持不变
public interface Subject {
public void handleData1();
public void handleData2();
public void handleData3();
}
public class MySubject implements Subject{
@Override
public void handleData1(){
System.out.println("业务1");
}
@Override
public void handleData2(){
System.out.println("业务3");
}
@Override
public void handleData3(){
System.out.println("业务3");
}
}
2.创建代理器:
public class SubjectInvocationHandler implements InvocationHandler {
//持有被代理对象引用
Subject realSubject;
public void setRealSubject(Subject realSubject) {
this.realSubject = realSubject;
}
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("打印日志上传");
//调用被代理对象的方法
method.invoke(realSubject, objects);
return null;
}
}
3.调用:
//创建被代理类对象
Subject realSubject = new MySubject();
//创建代理器,该对象并不是真正的代理对象
SubjectInvocationHandler handler = new SubjectInvocationHandler();
handler.setRealSubject(realSubject);
//生成代理对象
Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(),
realSubject.getClass().getInterfaces(), handler);
//调用代理对象的方法
subject.handleData1();
4.输出结果:
2019-12-26 15:48:54.280 3244-3244/com.example.serializationapplication I/System.out: 打印日志上传
2019-12-26 15:48:54.280 3244-3244/com.example.serializationapplication I/System.out: 业务1
第一步:创建代理器实现
InvocationHandler
接口,重写invoke()
方法,代理器还持有被代理类的引用。在invoke()
方法中调用被代理对象的方法。
第二步:通过代理器和被代理对象创建真正的代理对象,Proxy.newProxyInstance()
创建代理对象,第一个参数是代理器的类加载器,第二个参数是被代理对象的接口,第三个参数是代理器。
在调用代理对象的方法时都会回调到代理器的invoke()
方法,我们可以在invoke()
方法中实现我们自己的逻辑。
参考链接:Java 动态代理作用是什么?