Spring AOP学习
2018-02-05 本文已影响9人
jwfy
AOP 概念了解
AOP(Aspect Oriented Programming)面向切面编程,是针对面向对象编程的一种补充,同时也是spring中第二个最核心的功能,例如可以进行权限认证,日志输出等,可以无侵入的对原来的功能进行切面加入自定义的非业务功能。
- 切面(AspectJ):对横切关注点的抽象
- 连接点(Joinpoint):被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
- 通知(Advice):AOP框架在特定的切入点执行的增强处理,分为前置、后置、异常、最终、环绕五种情况
- 切入点(Pointcut):需要拦截的点
- 引入:将方法或字段添加到被处理的类中。Spring允许引入新的接口到任何被处理的对象。例如,你可以使用一个引入,使任何对象实现IsModified接口,以此来简化缓存
- 目标对象:被AOP框架进行增强处理的对象,也被称为被增强的对象
- AOP代理:AOP框架创建的对象,简单的说,代理就是对目标对象的加强。Spring中的AOP代理可以是JDK动态代理,也可以是CGLIB代理
- 织入(Weaving):将增强处理添加到目标对象中,并创建一个被增强的对象的过程。
在spring中AOP代理对象依旧是由IOC容器管理着,在具体代理生成中可以由java动态代理生成也可以由cglib字节码增强完成,具体运行中会根据具体情况选择合适的代码生成方式。如果是接口,则只会使用动态代理生成
在了解完AOP的基础知识后,介绍AOP的两种使用方法,XML配置和注解
XML 配置
<bean id="people" class="com.demo.Aop.People" />
<bean id="peopleAop" class="com.demo.Aop.PeopleAop" />
<aop:config>
<aop:pointcut id="pc" expression="execution(* com.demo.Aop.*.*(..))" />
<aop:aspect ref="peopleAop">
<aop:after method="after" pointcut-ref="pc" />
<aop:before method="before" pointcut-ref="pc" />
<aop:around method="around" pointcut-ref="pc" />
<aop:after-returning method="afterReturn" pointcut-ref="pc" />
<aop:after-throwing method="excep" pointcut-ref="pc" />
</aop:aspect>
</aop:config>
public class PeopleAop {
public void before(){
System.out.println("before");
}
public void after(){
System.out.println("after");
}
public Object around(ProceedingJoinPoint pj){
System.out.println("around before");
Object obj = null;
try {
obj = pj.proceed();
} catch (Throwable throwable) {
}
System.out.println("around after");
return obj;
}
public void afterReturn(){
System.out.println("after return");
}
public void excep(){
System.out.println("error!!!!");
}
}
public class People {
public void say() {
System.out.println("chinese");
}
}
最后的执行结果
image.png
看图得出先后顺序是before、around、after、after return。但是xml配置的执行顺序就真的是这样的么?
当我把上面xml配置的before和around换一个位置之后输出到结果
image.png结果发生了变化,成为了around、before、after、after return
注解
<bean class="com.demo.Aop.AnimalImpl" id="animal" />
<bean class="com.demo.Aop.AnimalAop" id="animalAop" />
<!-- 上面两个bean 只是为了便于说明代码,也可以使用component-scan 配合相关注解完成-->
<aop:aspectj-autoproxy />
<!-- AOP注解核心配置,会生成相关的代理类-->
// 接口类
public interface Animal {
void sleep(String name);
}
// 实现类
public class AnimalImpl implements Animal {
public AnimalImpl() {
System.out.println("init");
}
public void sleep(String name) {
System.out.println(name + " sleep");
}
}
// 切面类
public class AnimalAop {
@Pointcut("execution(* com.demo.Aop.*.*(..))")
public void pointCut(){}
// 定义一个切点,会选择com.demo.Aop下面所有的类
@Around("pointCut() && args(name)")
public Object around(ProceedingJoinPoint pj, String name){
// 定义为around注解,添加了切点,并且同时加上了参数
Object obj = null;
System.out.println(name + " around before");
try {
obj = pj.proceed();
} catch (Throwable throwable) {
throwable.printStackTrace();
}
System.out.println(name + " around after");
return obj;
}
@Before("pointCut() && args(name)")
public void before(String name){
System.out.println(name + " animal before");
}
@After("execution(* com.demo.Aop.*.*(..))")
public void after(){
// 这个直接使用了execution,而没有使用已经定义好的切点
System.out.println("animal after");
}
}
执行结果
image.png
在原本的实现类实现之后,执行的先后顺序为around、before、after、after return
不过这里是没有XML注解的那种先后执行顺序,所有的执行顺序都是由spring自身决定的
在当前的demo中可能注意到了,所使用的AnimalImpl是继承自Animal接口的,如果改成没有接口的情况呢?
image.png image.png很明显 在使用接口的时候,spring会使用java的动态代理实现,否则会使用cglib实现代理功能
demo基本上就完成了,后面的学习文章会具体分析XML配置和注解配置的实现细节以及同异