(06Day)
接下来我们来看看Spring的AOP(面向切面编程),这个AOP是和我们前面学的IOC或DI是spring的两大基石,同时AOP是 那对OOP的一个补充,AOP编程的主要关注对象是切面,这。那么为什么需要AOP呢?我举个例子就能说明为什么需要AOP。比如我们需要在所有的方法执行前都打印出对应的方法和参数用来做一个日志管理。如果我们不用AOP或者动态代理,那么我们就只有到每一个方法中添加一句输出语句,如果某天我需要在所有输出语句前打印出日志两个字的话是不是需要又倒回去在每个方法中的输出语句中修改,那么这样岂不是很麻烦呢?所以有了AOP和动态代理来解决这个问题。只要使用了这两个方法那么在每次修改的时候只需要修改一个地方就可以了。而且这样可以让方法更加专注的去实现业务代码。而不用去关心日志文件。这样在我那们定义日志等模块的时候只需要定义公共的功能,并且不必修改受影响的类。那么我们先来看一看上面说到的动态代理是如何实现的。
首先写一个处理业务的类(计算器为例)
package com.aop.helloWorld;
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
public int add(int i, int j) {
int result = i + j;
return result;
}
public int sub(int i, int j) {
int result = i - j;
return result;
}
public int mul(int i, int j) {
int result = i * j;
return result;
}
public int div(int i, int j) {
int result = i / j;
return result;
}
}
创建一个动态代理类
package com.aop.helloWorld;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
//动态代理类
public class ArithmeticCalculatorLoggingProxy {
//要代理的对象
private ArithmeticCalculator target;
public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) {
super();
this.target = target;
}
public ArithmeticCalculator getLoggingProxy(){
ArithmeticCalculator proxy = null;
//代理对象由哪一个类加载器负责加载
ClassLoader loader = target.getClass().getClassLoader();
//代理对象的类型,即其中有哪些方法
Class[] interfaces = new Class[]{ArithmeticCalculator.class};
//当调用代理对象其中的方法时,该执行的代码
InvocationHandler h = new InvocationHandler() {
/*
* proxy:正在返回的代理对象,一般情况下,在invoke方法中都不使用该对象
* method:正在被调用的方法
* args:调用方法时传入的参数
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methodName = method.getName();
//日志
System.out.println("执行的方法是:"+methodName+"参数为:"+Arrays.asList(args));
//执行方法
Object result = method.invoke(target, args);
//日志
System.out.println("执行的方法是:"+methodName+"结果为:"+result);
return result;
}
};
proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
return proxy;
}
}
最后在测试类中进行测试
package com.aop.helloWorld;
public class Main01 {
public static void main(String[] args) {
//使用动态代理来解决日志问题
ArithmeticCalculator target = new ArithmeticCalculatorImpl();
ArithmeticCalculator proxy = new ArithmeticCalculatorLoggingProxy(target).getLoggingProxy();
int result = proxy.add(1, 2);
System.out.println("-->"+result);
result = proxy.mul(2, 3);
System.out.println("-->"+result);
}
}
这样就实现了动态代理来处理日志问题,那么既然有了动态带来为什么还要用AOP呢?其实在开发中确实可以这样用,但是这样写还是比较麻烦的,而且让一般的程序员去搞这个动态代理呢,要求有些高。所以就出现了更简单的AOP实现方法。
所以我们先来看一看AOP的几个基本的概念。
- 切面:横切关注点模块化的特殊对象。比如:在方法执行前的前置日志和后置日志。这两个方法都是横切关注点,把这两个类似的横切关注点放在一起就叫做日志切面。
- 通知:切面必须完成的工作,通俗来说就是切面中的每一个方法(切点)就称为一个通知。
- 目标:被通知的对象,就是要执行某些切面的方法。
- 代理:向目标对象应用通知之后创建的对象,就类似上边动态代理主函数中的proxy对象。
- 连接点:程序执行的某个特点的位置,是一个物理存在,比如说类的某个方法调用前或者抛出异常的时候。连接点由两个基本信息决定。第一个就是方法,这个方法表示程序的执行点。还有一个就是相对点,执行的方位,就是哪个方法执行前还是后。比如说add()方法执行之前。
- 切点:切点是指AOP通过切点定位到特定的连接点。用类别来说:连接点相当于数据库中的记录,而切点相当于查询条件。