1 AOP能解决什么问题
1.1 提出问题
1.1.1 情景:数学计算器
1.1.1.1 要求
①执行加减乘除运算
②日志:在程序执行期间追踪正在发生的活动
ArithmeticCalculator.java
public interface ArithmeticCalculator {double add(double a, double b);double sub(double a, double b);double mul(double a, double b);double div(double a, double b);
}
ArithmeticCalculatorImpl.java
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {@Overridepublic double add(double a, double b) {return a + b;}@Overridepublic double sub(double a, double b) {return a - b;}@Overridepublic double mul(double a, double b) {return a * b;}@Overridepublic double div(double a, double b) {return a / b;}
}
1.1.1.2 常规实现
ArithmeticCalculatorImpl.java
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {@Overridepublic double add(double a, double b) {System.out.println("The method add begins with [" + a + ", " + b + "]");double result = a + b;System.out.println("The method add ends with " + result);return result;}@Overridepublic double sub(double a, double b) {System.out.println("The method sub begins with [" + a + ", " + b + "]");double result = a - b;System.out.println("The method sub ends with " + result);return result;}@Overridepublic double mul(double a, double b) {System.out.println("The method sub begins with [" + a + ", " + b + "]");double result = a * b;System.out.println("The method sub ends with " + result);return result;}@Overridepublic double div(double a, double b) {System.out.println("The method sub begins with [" + a + ", " + b + "]");double result = a / b;System.out.println("The method sub ends with " + result);return result;}
}
1.1.1.3 问题
①代码混乱:越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀。每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点。
②代码分散: 以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化,必须修改所有模块。
1.2 动态代理
1.2.1 动态代理的原理
代理设计模式的原理:使用一个代理将原本对象包装起来,然后用该代理对象”取代”原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
1.2.2 动态代理的方式
- 基于接口实现动态代理: JDK动态代理
- 基于继承实现动态代理: Cglib、Javassist动态代理
1.3 数学计算器的改进(JDK动态代理)
1.3.1 日志处理器
CalculatorLoggingHandler.java
public class CalculatorLoggingHandler implements InvocationHandler {private Object target;public CalculatorLoggingHandler(Object target) {this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("The method " + method.getName() + "() begins with " + Arrays.toString(args));Object result = method.invoke(target, args);System.out.println("The method " + method.getName() + "() ends with " + result);return result;}public static Object createProxy(Object target) {return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new CalculatorLoggingHandler(target));}
}
1.3.2 测试代码
Main.java
public class Main {public static void main(String[] args) {ArithmeticCalculatorImpl arithmeticCalculator = new ArithmeticCalculatorImpl();ArithmeticCalculator proxy = (ArithmeticCalculator) CalculatorLoggingHandler.createProxy(arithmeticCalculator);System.out.println(proxy.add(12, 13));}
}
1.3.3 测试结果
The method add() begins with [12.0, 13.0]
The method add() ends with 25.0
25.0