概念
AOP(Object-Oriented Programming)面向对象编程,允许开发者定义纵向的关系,但并适用于定义横向的关系,导致了大量代码的重复,而不利于各个模块的重用。
AOP(Aspect-Oriented Programming),一般称为面向切面编程,作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,这个模块被命名为
“
切面
”
(
Aspect),减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。可用于权限认证、日志、事务处理等。
实现方式
AOP实现的关键在于 代理模式,
AOP
代理主要分为静态代理和动态代理。静态代理的代表为AspectJ;动态代理则以
Spring AOP
为代表。
(
1)
AspectJ
是静态代理的增强,所谓静态代理,就是
AOP
框架会在编译阶段生成
AOP
代理
类,因此也称为编译时增强,他会在编译阶段将
AspectJ(
切面
)
织入到
Java
字节码中,运行的时候就是增强之后的AOP
对象。
(2
)
Spring AOP
使用的动态代理,所谓的动态代理就是说
AOP
框架不会去修改字节码,而是每次
运行时在内存中临时为方法生成一个
AOP
对象,这个
AOP
对象包含了目标对象的全部方法,并且在
特定的切点做了增强处理,并回调原对象的方法。
什么是切面 Aspect?
aspect 由
pointcount
和
advice
组成,切面是通知和切点的结合。 它既包含了横切逻辑的定义, 也包括了连接点的定义
. Spring AOP
就是负责实施切面的框架
, 它将切面所定义的横切逻辑编织到切面所指定的连接点中
. AOP
的工作重心在于如何将增强编织目标对象的连接点上
, 这里包含两个工作
:
1. 如何通过
pointcut
和
advice
定位到特定的
joinpoint
上.
2. 如何在
advice
中编写切面代码
.
可以简单地认为,
使用
@Aspect
注解的类就是切面
![](https://i-blog.csdnimg.cn/blog_migrate/890fb1de1206a237d4388298f80d38da.png)
JDK动态代理和CGLIB动态代理的区别
Spring AOP
中的动态代理主要有两种方式,
JDK
动态代理和
CGLIB
动态代理
JDK动态代理只提供接口的代理,不支持类的代理。核心
InvocationHandler
接口和
Proxy类,InvocationHandler
通过
invoke()
方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;接着,Proxy
利用
InvocationHandler
动态创建一个符合某一接口的的实例,
生成目标类的代理对象。
如果代理类没有实现 InvocationHandler
接口,那么
Spring AOP
会选择使用
CGLIB
来动态代理目标类。CGLIB
(
Code Generation Library
),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP
。CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为
fifinal
,那么它是无法使用CGLIB做动态代理的。
静态代理与动态代理区别在于生成AOP
代理对象的时机不同,相对来说
AspectJ的静态代理方式具 有更好的性能,但是
AspectJ
需要特定的编译器进行处理,而
Spring AOP则无需特定的编译器处 理
Spring通知有哪些类型?
在AOP
术语中,切面的工作被称为通知,实际上是程序执行时要通过
SpringAOP框架触发的代码段。
Spring
切面可以应用
5
种类型的通知:
1. 前置通知(
Before
):在目标方法被调用之前调用通知功能;
2. 后置通知(
After
):在目标方法完成之后调用通知,此时不会关心方法的输出是什么;
3. 返回通知(
After-returning
):在目标方法成功执行之后调用通知;
4. 异常通知(
After-throwing
):在目标方法抛出异常后调用通知;
5. 环绕通知(
Around):通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为。
前置通知
准备一个Aspect切面类
public class MyAspects {
//方法名可以随意
public void before(JoinPoint joinPoint,String title){
System.out.println("这是前置增强程序");
}
}
添加配置
测试程序
后置通知
public class MyAspects {
//方法名可以随意
public void after(JoinPoint joinPoint,Object returnVal){
System.out.println("这是后置增强程序");
}
}
添加配置
后置通知是在方法返回之后的增强程序,所以可以获取到方法的返回值。
我们修改业务, 增加返回值
public class MyAspects {
//方法名可以随意
public void after(JoinPoint joinPoint,Object returnVal){
System.out.println("这是后置增强程序");
System.out.println("被增强方法的返回值为:"+returnVal);
}
}
测试程序
环绕通知, 异常通知, 最终异常
程序相同, 配置文件中更改方法名即可, 此处略写
使用Advisor的方式进行AOP的配置
前置通知
我们自己写一个类,实现接口MethodBeforeAdvice
public class MyBeforeAdvice implements MethodBeforeAdvice {
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("advisor前置通知");
}
}
添加配置
环绕通知
自己写一个类,实现接口MethodBeforeAdvice
public class MyInterceptor implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("{{环绕通知开始}}");
Object obj = invocation.proceed(); //接受返回值
System.out.println("{{环绕通知结束}}");
return obj; // 返回返回值
}
}
添加配置
后置通知, 异常通知, 最终通知, 略
各种通知的执行顺序
前置通知
环绕通知开始部分
[业务部分]
///有可能出现异常通知,异常出现,环绕和后置不会再执行
环绕通知结束
后置通知
最终通知(无论是否有异常都必须有后置通知)