对于AOP的理解一直很模糊,学习Spring的视频正好讲到,老师讲的很好,我也稍微懂了点,在这里针对其内容整理下。
简单概念
AOP(Aspect-Oriented Programming)即面向切面编程,是对于OOP的补充。不同于OOP的面向纵向编程,AOP面向的是切面即横向编程,她将纵向的某个流程提取出来,给其添加相应的功能。这里不做过多的解释先来看一个例子。
代码示例
需求
实现一个计算机类,能进行加减乘除运算,而且还需要添加日志功能记录进行了那些运算和调试功能在运行方法时就返回结果!
接口
interface CalculatorInterface {
int add(int a, int b);
int sub(int a, int b);
int mul(int a, int b);
int div(int a, int b);
}
实现类计算器类:
package cnjxufe.beans_12_AOP;
/**
* @author hsw
* @create 2018-11-07 15:37
*/
public class Calculator implements CalculatorInterface {
@Override
public int add(int a, int b) {
System.out.println("add方法被调用,参数 : a = " + a + ", b = " + b);
int result = a + b;
System.out.println("a + b = " + result);
return result;
}
@Override
public int sub(int a, int b) {
System.out.println("sub,参数 : a = " + a + ", b = " + b);
int result = a - b;
System.out.println("a - b = " + result);
return result;
}
@Override
public int mul(int a, int b) {
System.out.println("mul方法被调用,参数 : a = " + a + ", b = " + b);
int result = a * b;
System.out.println("a * b = " + result);
return result;
}
@Override
public int div(int a, int b) throws ArithmeticException{
System.out.println("div方法被调用,参数 : a = " + a + ", b = " + b);
int result = a / b;
System.out.println("a / b = " + result);
return result;
}
}
这样每次我们调用计算方法时都会有日志与结果的输出。
问题
上面的代码是没有用到AOP编程的,这样做会造成两个问题:
- 代码混乱:越来越多的非业务需求(比如上面的日志记录和结果显示)会是业务处理代码急剧膨胀,业务方法除了处理业务逻辑外还要兼顾其他内容。
-代码分散:单一的需求相同代码在多个模块或方法中分散,一旦需求变更就必须改变多出的模块,这会给代码的维护和更新带来巨大成本!
解决问题
如何解决上面两个问题呢?这里我们就要使用AOP了!这里先不用Spring的AOP,而是用动态代理来实现AOP。要了解动态代理原理就要先了解代理设计模式,可以自己去了解下,一遍理解下面的代码:
之前的计算机实现类不动,新建一个计算机原始类其每个方法只实现业务逻辑:
package cnjxufe.beans_12_AOP;
/**
* @author hsw
* @create 2018-11-07 16:05
*/
public class OriginalCalculator implements CalculatorInterface {
@Override
public int add(int a, int b) {
return a + b;
}
@Override
public int sub(int a, int b) {
return a - b;
}
@Override
public int mul(int a, int b) {
return a * b;
}
@Override
public int div(int a, int b) {
return a / b;
}
}
再实现动态代理类:
package cnjxufe.beans_12_AOP;
import java.lang.reflect.Proxy;
/**
* @author hsw
* @create 2018-11-07 16:06
*/
public class DynamicProxy {
// 要代理的对象
private CalculatorInterface target;
public DynamicProxy(CalculatorInterface target) {
this.target = target;
}
public CalculatorInterface getDynamicProxy() {
CalculatorInterface proxy = null;
ClassLoader loader = target.getClass().getClassLoader();
proxy = (CalculatorInterface) Proxy.newProxyInstance(loader, new Class[]{CalculatorInterface.class},
(object, method, args) -> {
System.out.println(method.getName() + "方法被调用,参数 : a = " + args[0] + ", b = " + args[1]);
int result = (int) method.invoke(target, args[0], args[1]);
System.out.println("a " + method.getName() + " b = " + result);
return result;
});
return proxy;
}
}
其中lambda表达式(这个就是我们使用代理对象其中的方法时,被调用的方法!)代表的是:
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
};
参数解释:
proxy:正在返回的代理对象,一般情况下invoke方法不使用该对象!
method:正在被调用的方法
args:被调用的方法的入参
Main类执行两个对象的计算方法:
public static void main(String[] args) {
System.out.println("没有使用代理的结果:");
Calculator calculator = new Calculator();
System.out.println(calculator.add(12, 10));
System.out.println("以下是使用代理后的结果:");
CalculatorInterface calculatorWithProxy = new OriginalCalculator();
CalculatorInterface proxy = new DynamicProxy(calculatorWithProxy).getDynamicProxy();
System.out.println(proxy.add(12, 10));
}
结果:
原理:
动态代理模式实现了AOP,让一个代理包裹住原对象的业务方法,当用户使用对象的某个方法时,其必先经过代理的某个对应的方法,然后由代理对象决定何时和怎样调被代理对象!
AOP简介
AOP是一种新的方法论,是对传统oop的补充,AOP的主要编程对象是切面,在上述例子中我们添加的代码并不是针对整个逻辑流程而编码,而是为了四个计算方法,这个四个方法在整个流程中属于同一级,类似于一个切面。嗯,,,可以这么理解!
AOP的好处:
- 每个事务逻辑位于一个位置,代码不分散,便于维护和升级
- 代码模块更加简洁,只包含核心代码
AOP概念
切面
横切关注点(跨越应用程序多个模块的功能,比如位置功能)被模块化的多个对象。像上面例子中的日志功能就是一个切面!
通知
切面必须要完成的工作,在切面中的每一个方法就可以被称之为通知!
目标
被通知的对象 ,上述例子中的add,sub等计算方法就是目标。
代理
就是上面例子中的proxy对象
连接点
程序执行的某个特定的位置:如类某个方法调用前、调用后,方法抛出异常后等。连接点有两个信息确定:方法表示程序执行点相对点表示方位。比如说add方法执行前就是一个连接点,执行点就是add方法,方位为执行前。