其实今天在理解Spring的过程中,发现对于AOP这个东西竟然还是有些云里雾里的感觉。在理解动态代理的过程中也有一些不太理解的东西。
我所看的大致的教学视频是这样的:
有一个这样的需求:就是一个日志需求,要求在程序执行期间追踪正在发生的活动。
比如,我有一个接口:
public interface ArithmeticCalculator {
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 ArithmeticCalculatorLoggingImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
System.out.println("the method add begins with [" + i + "," + j + "]");//前置的日志方法
int result = i + j;
System.out.println("the method add edd with " + result);//后置的日志方法
return result;
}
@Override
public int sub(int i, int j) {
System.out.println("the method sub begins with [" + i + "," + j + "]");//前置的日志方法
int result = i - j;
System.out.println("the method sub edd with " + result);//后置的日志方法
return result;
}
@Override
public int mul(int i, int j) {
System.out.println("the method mul begins with [" + i + "," + j + "]");//前置的日志方法
int result = i * j;
System.out.println("the method mul edd with " + result);//后置的日志方法
return result;
}
@Override
public int div(int i, int j) {
System.out.println("the method div begins with [" + i + "," + j + "]");//前置的日志方法
int result = i / j;
System.out.println("the method div edd with " + result);//后置的日志方法
return result;
}
}
很显然我们发现存在两个问题:
1.代码混乱:随着业务需求的增加,所有的业务方法急剧膨胀,每个方法在处理核心逻辑问题的同时还必须兼顾到其他的多个关注点。
2.代码分散:以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化,那就必须修改所有模块了吧。
解决的办法可以是:使用动态代理!
代理设计模式的原理是使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要经过代理,代理对象决定是否以及何时将方法调用到原始对象上。
我们看下面这个类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ArithmeticCalculatorLoggProxy {
//要代理的对象
private ArithmeticCalculator target;
public ArithmeticCalculator getLoggingProxy() {
ArithmeticCalculator proxy = null;
//代理对象由哪一个类加载器来加载
ClassLoader loader = target.getClass().getClassLoader();
//代理对象的类型,即其中有哪些方法
Class[] interfaces = new Class[]{ArithmeticCalculator.class};
//当调用代理对象其中的方法时,该执行的代码
InvocationHandler h = new InvocationHandler() {
/**
* proxy: 正在返回的那个代理对象。一般情况下不使用。
* method: 正在被调用的方法
* args: 调用方法时传入的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
//日志
System.out.println("the method of " + methodName + "is starts with " + Arrays.asList(args));
//执行方法
Object result = method.invoke(target, args);
//日志
System.out.println("the method of" + methodName + "is end with " + result);
return result;
}
};
proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader , interfaces, h);
return proxy;
}
}
通过这样操作,就可以在开始测试了。
新建一个测试类:
public class Main {
public static void main(String[] args) {
ArithmeticCalculator arithmeticCalculator = new ArithmeticCalculatorImpl();//纯净的。在代理之前的对象
ArithmeticCalculator proxy = new ArithmeticCalculatorLoggProxy(arithmeticCalculator).getLoggingProxy();//将要代理的对象放入其中,完成代理的操作
//直接使用代理后的对象
int result = proxy.add(2, 5);
proxy.div(12, 3);
}
}
废话就放在后头好了,已经许久没有看自己的博客,当初开博客的初衷是希望自己通过记录分享自己在java学习之路的一些东西,也能在这个过程中提高自己。水平有限,说不上心得,纯粹当是日记吧。
现在已经在一家网络科技公司入职,想起来不得不感谢这家公司对我信任,愿意给我一个学习发展、提高自己的机会吧。
因为公司所用的框架主要是SpringMVC,所以我也就理所当然地要加强自己SpringMVC框架的学习了。进去之后才发现自己对于Spring和Struts2的理解掌握其实都还很浅,所以自己在工作之余中找出了Spring的学习视频,希望重新深入地对这个框架进行学习掌握。
瞎bb了一些,没有思绪写啊。。。。。。。。。。。。。。。