一个小需要:给原有办法增加日志打印
假如当初咱们有一个类Calculator,代表一个计算器,它能够进行加减乘除操作
public class Calculator { //加 public int add(int a, int b) { int result = a + b; return result; } //减 public int subtract(int a, int b) { int result = a - b; return result; } //乘法、除法...}
现有一个需要:在每个办法执行前后打印日志。你有什么好的计划?
间接批改
很多人最直观的想法是间接批改Calculator类:
public class Calculator { //加 public int add(int a, int b) { System.out.println("add办法开始..."); int result = a + b; System.out.println("add办法完结..."); return result; } //减 public int subtract(int a, int b) { System.out.println("subtract办法开始..."); int result = a - b; System.out.println("subtract办法完结..."); return result; } //乘法、除法...}
下面的计划是有问题的:
- 间接批改源程序,不合乎开闭准则。应该对扩大凋谢,对批改敞开
- 如果Calculator有几十个、上百个办法,批改量太大
- 存在反复代码(都是在外围代码前后打印日志)
- 日志打印硬编码在代理类中,不利于前期保护:比方你花了一上午终于写完了,组长通知你这个性能勾销,于是你又要关上Calculator花十分钟删除日志打印的代码!
所以,此种计划PASS!
动态代理实现日志打印
“动态代理”四个字蕴含了两个概念:动态、代理。咱们先来理解什么叫“代理”,至于何为“动态”,须要和“动静”比照着讲。
代理是一种模式,提供了对指标对象的间接拜访形式,即通过代理拜访指标对象。如此便于在指标实现的根底上减少额定的性能操作,前拦挡,后拦挡等,以满足本身的业务需要。
援用博客:Java动态代理和动静代理 - 纪煜楷 - 博客园
援用自:Java动态代理和动静代理 - 纪煜楷 - 博客园
罕用的代理形式能够粗分为:动态代理和动静代理。
动态代理的实现比较简单:编写一个代理类,实现与指标对象雷同的接口,并在外部保护一个指标对象的援用。通过结构器塞入指标对象,在代理对象中调用指标对象的同名办法,并增加前拦挡,后拦挡等所需的业务性能。
按下面的形容,代理类和指标类须要实现同一个接口,所以我打算这样做:
- 将Calculator抽取为接口
- 创立指标类CalculatorImpl实现Calculator
- 创立代理类CalculatorProxy实现Calculator
接口
/** * Calculator接口 */public interface Calculator { int add(int a, int b); int subtract(int a, int b);}
指标对象实现类
/** * 指标对象实现类,实现Calculator接口 */public class CalculatorImpl implements Calculator { //加 public int add(int a, int b) { int result = a + b; return result; } //减 public int subtract(int a, int b) { int result = a - b; return result; } //乘法、除法...}
代理对象实现类
/** * 代理对象实现类,实现Calculator接口 */public class CalculatorProxy implements Calculator { //代理对象外部保护一个指标对象援用 private Calculator target; //构造方法,传入指标对象 public CalculatorProxy(Calculator target) { this.target = target; } //调用指标对象的add,并在前后打印日志 @Override public int add(int a, int b) { System.out.println("add办法开始..."); int result = target.add(a, b); System.out.println("add办法完结..."); return result; } //调用指标对象的subtract,并在前后打印日志 @Override public int subtract(int a, int b) { System.out.println("subtract办法开始..."); int result = target.subtract(a, b); System.out.println("subtract办法完结..."); return result; } //乘法、除法...}
应用代理对象实现加减乘除,并且打印日志
public class Test { public static void main(String[] args) { //把指标对象通过结构器塞入代理对象 Calculator calculator = new CalculatorProxy(new CalculatorImpl()); //代理对象调用指标对象办法实现计算,并在前后打印日志 calculator.add(1, 2); calculator.subtract(2, 1); }}
动态代理示意图
动态代理的长处:能够在不批改指标对象的前提下,对指标对象进行性能的扩大和拦挡。然而它也仅仅解决了上一种计划4大毛病中的第1点:
- 间接批改源程序,不合乎开闭准则。应该对扩大凋谢,对批改敞开 √
- 如果Calculator有几十个、上百个办法,批改量太大 ×
- 存在反复代码(都是在外围代码前后打印日志) ×
- 日志打印硬编码在代理类中,不利于前期保护:比方你花了一上午终于写完了,组长通知你这个性能勾销,于是你又要关上Calculator花十分钟删除全副新增代码!×
- *
动态代理的问题
下面案例中,代理类是咱们当时编写的,而且要和指标对象类实现雷同接口。因为CalculatorImpl(指标对象)须要日志性能,咱们即编写了CalculatorProxy(代理对象),并通过结构器传入CalculatorImpl(指标对象),调用指标对象同名办法的同时增加加强代码。
然而这里有个问题!代理对象结构器的参数类型是Calculator,这意味着它只能承受Calculator的实现类对象,亦即咱们写的代理类CalculatorProxy只能给Calculator做代理,它们绑定死了!
如果当初咱们零碎须要全面革新,给其余类也增加日志打印性能,就得为其余几百个接口都各自写一份代理类...
本人手动写一个类并实现接口切实太麻烦了。认真一想,咱们其实想要的并不是代理类,而是代理对象!那么,是否让JVM依据接口主动生成代理对象呢?
比方,有没有一个办法,我传入接口,它就给我主动返回代理对象呢?
答案是必定的。