AOP前奏
1.情景:数学计算器
这里我们模拟一个计算器,添加日志功能。
①执行加减乘除运算
②日志:在程序执行期间追踪正在发生的活动
2)常规实现
存在的问题:
- ①代码混乱:越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀。每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点。
- ②代码分散: 以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化,必须修改所有模块。
动态代理
动态代理原理:
代理设计模式的原理:使用一个代理将原本对象包装起来,然后用该代理对象”取代”原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
动态代理的方式
- 1)基于接口实现动态代理: JDK动态代理
- 2)基于继承实现动态代理: Cglib、Javassist动态代理
这里对计算器类进行简化:
public interface Mathl {
int add(int i,int j);
int sub(int i,int j);
int mul(int i,int j);
int div(int i,int j);
}
public class MathImpl implements Mathl {
@Override
public int add(int i, int j) {
return i + j;
}
@Override
public int sub(int i, int j) {
return i-j;
}
@Override
public int mul(int i, int j) {
return i*j;
}
@Override
public int div(int i, int j) {
return i/j;
}
}
写一个类模拟生成日志的方法:
public class MyLogger {
public static void before(String methodname, String args){
System.out.println("method: " + methodname+",arguments: " + args);
}
public static void after(String methodname,Object result){
System.out.println("method: " + methodname +",result: " +result);
}
}
写一个代理类:
public class ProxyUtil{
public ProxyUtil(MathImpl mathImpl) {
this.mathImpl = mathImpl;
}
private MathImpl mathImpl;
public Object getProxy(){
ClassLoader loader = this.getClass().getClassLoader();
Class[] interfaces = mathImpl.getClass().getInterfaces();
return Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MyLogger.before(method.getName(), Arrays.toString(args));
Object result = method.invoke(mathImpl, args);
MyLogger.after(method.getName(),result);
return result;
}
});
}
}
测试:
public class Test {
public static void main(String[] args) {
// Mathl math = new MathImpl();
// int result = math.add(1, 5);
// System.out.println(result);
ProxyUtil util = new ProxyUtil(new MathImpl());
Mathl math =(Mathl)util.getProxy();
int add = math.add(1, 3);
System.out.println(add);
int mul = math.mul(2,3);
System.out.println(mul);
}
}
结果: