大家好,欢迎来到IT知识分享网。
代理(Proxy)的概念很好理解,就是在我们使用某个类A(被代理对象)的时候,不是直接使用该类A本身,而是通过新建一个类B(代理类),在类B中调用类A,从而可以实现通过使用类B来达到使用类A的目的。同时我们可以在类B中对类A的功能进行扩展。这样就可以在不改动类A的前提之下,加入我们新的功能需求,可以实现增强类A的功能。
举个例子,假设现在有一个类A:
class A{ public void method1(String p) { System.out.print("Hello "); System.out.println(p); } private void method2(String p) { System.out.print("Hello "); System.out.println(p); } }
不使用代理的时候我们直接调用类A的method1:
public static void main(String[] args) { A a = new A(); a.method1("Java"); }
假设现在有个需求,要求打印出类A中method1的入参和该方法执行的开始和结束时间,但是不能修改类A。我们可以用下面两种方式实现:
第一种,我们创建一个类B,在类B中注入一个类A的对象a,同时编写一个和类A.method1同样结构的方法,并在这个方法中调用a.method1(),代码如下:
class B{ private A a; public B(A a) { this.a = a; } public void method1(String p) { System.out.println("request param : " + p); System.out.println("method start at " + new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss:SSS").format(new Date())); a.method1(p); System.out.println("method end at " + new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss:SSS").format(new Date())); } }
然后我们可以这么调用:
public static void main(String[] args) { B b = new B(new A()); b.method1("Java"); }
这种实现方式需要满足两个条件:
- 类A不能是抽象类
- method1必须是public的
第二种,我们可以创建一个类B来继承类A,然后重写类A的method1,代码如下:
class B extends A{ @Override public void method1(String p) { System.out.println("request param : " + p); System.out.println("method start at " + new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss:SSS").format(new Date())); super.method1(p); System.out.println("method end at " + new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss:SSS").format(new Date())); } }
然后我们可以这么调用:
public static void main(String[] args) { B b = new B(); b.method1("Java"); }
这种实现方式需要满足条件:
- 类A不能是final的
- 类A中的method1 必须是public的,并且不能是final的
第三种,如果类A是实现了IA接口的,并且方法method1是重写的方法,那么我们可以创建一个类B也实现接口IA,然后注入类A,代码如下:
interface IA { void method1(String p); } class A implements IA { @Override public void method1(String p) { System.out.print("Hello "); System.out.println(p); } private void method2(String p) { System.out.print("Hello "); System.out.println(p); } } class B implements IA { private A a; public B(A a) { this.a = a; } @Override public void method1(String p) { System.out.println("request param : " + p); System.out.println("method start at " + new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss:SSS").format(new Date())); a.method1(p); System.out.println("method end at " + new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss:SSS").format(new Date())); } }
调用方法同第一种方法。
这种方案跟第一种很相似,抽象出接口好处是可以提前约定好method1的特征,防止在B类中写的代理方法和A类的方法有出入。
这种方式需要满足条件:
- 类A(被代理类)和类B(代理类)都必须实现同一个接口
- 类B只能代理类A中实现接口的那些方法
以上三种方法都可以在不修改类A的基础上对类A的方法进行扩充,满足了开闭原则。
但是以上各种写法你都必须把类B一起编译打包,程序才能正常运行,这样的代理方式称之为静态代理,他的本质就是通过新增一个代理类来对被代理类的方法进行一个拦截,从而可以在调用被代理方法的前后增加我们自己需要的功能。
那么问题来了,大家可以看到上面的做法你必须手动写一个代理类,这样会导致应用的时候我们要编写很多的代理类,而我们实际使用中,很多的增强功能都是一些公共的处理,比如对接口的信息的打印、对一些异常进行统一的封装、对一些事务处理的统一管理等。如果我们使用上面的方式进行,就需要写无数个代理类。这显然不是我们想要的结果。
那么我们继续思考一下,如果可以在程序运行期间,根据我们的需要动态的构建一个代理类,然后执行完代理操作以后就释放掉,这样是不是就可以避免上述问题!这就是动态代理。
下一章中我们介绍动态代理的实现方式及应用场景。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/47584.html