面向切面编程:指在程序运行期间,将某段代码动态的切入到指定方法的指定位置进行运行的这种编程方式。
将某段代码(日志)动态的切入到指定方法(加减乘除)的指定位置(方法的开始,结束,异常)进行运行的这种编程方式
首先写一个接口:这个接口中有四个方法,分别计算加减乘除
public interface Caculator {
public int add(int i,int j);
public int sub(int i,int j);
public int mul(int i,int j);
public int div(int i,int j);
}
写这个接口的实现类,并实现接口中的抽象方法
public class MyMath implements Caculator {
public int add(int i, int j) {
return i+j;
}
public int sub(int i, int j) {
return i-j;
}
public int mul(int i, int j) {
return i*j;
}
public int div(int i, int j) {
return i/j;
}
}
写一个日志工具类
public class LogUtils {
public static void logStart(Method method,Object...args){
System.out.println("【"+method.getName()+"】方法开始执行,用的参数列表【"+ Arrays.asList(args)+"】");
}
public static void logReturn(Method method,Object result){
System.out.println("【"+method.getName()+"】方法正常执行完成,计算结果是:"+result);
}
public static void logException(Method method,Exception e){
System.out.println("【"+method.getName()+"】方法执行出现异常了,异常信息是:"+e+";这个异常通知");
}
public static void logEnd(Method method){
System.out.println("【"+method.getName()+"】方法最终结束了");
}
}
写一个动态代理类:
public class CaculatorProxy {
/*
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
*/
/**
* 为传入的参数参数创建一个代理对象
* Caculator caculator:被代理对象
*/
public static Caculator getProxy(final Caculator caculator){
Object proxy = Proxy.newProxyInstance(
caculator.getClass().getClassLoader(),
caculator.getClass().getInterfaces(),
new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
LogUtils.logStart(method,args);
result = method.invoke(caculator, args);
LogUtils.logReturn(method,result);
} catch (Exception e) {
LogUtils.logException(method,e);
}finally {
LogUtils.logEnd(method);
}
return result;
}
}
);
return (Caculator) proxy;
}
}
写一个测试类:
public class MyTest {
@Test
public void test(){
Caculator proxy = CaculatorProxy.getProxy(new MyMath());
proxy.add(1,2);
}
}
由此可以看出,使用动态代理的方式很复杂,代码写起来也很麻烦,Spring的AOP可以解决这种问题。
AOP的底层原理就是动态代理