Spring 的 AOP
AOP 思想介绍
Spring 中的 aop 概念
Spring 实现 aop 的原理
动态代理(优先)
被代理对象必须要实现接口,才能产生代理对象。如果没有接口将不能使用动态代理技术
cglib 代理(没有接口)
第三方代理技术,cglib 代理。可以对任何类生成代理。代理的原理是对目标对象进行继承代理。 如果目标对象被 final 修饰。那么该类无法被 cglib 代理。
aop 名词学习
1.导 AOP 相关的 jar 包
- spring-aspects-4.2.4.RELEASE.jar
- spring-aop-4.2.4.RELEASE.jar
- com.springsource.org.aopalliance-1.0.0.jar
- com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
2.准备目标对象
package com.tobeshrek.test.aop.service;
/**
* AOP测试service层
* @author 李国豪
* @date:2020年1月13日
*/
public interface UserService {
void save();
void update();
}
package com.tobeshrek.test.aop.service.impl;
import com.tobeshrek.test.aop.service.UserService;
/**
* 测试接口实现类
* @author 李国豪
* @date:2020年1月13日
*/
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("保存用户!");
}
@Override
public void update() {
@SuppressWarnings("unused")
int i = 1/0;//测试异常流程
System.out.println("更新用户!");
}
}
3.准备通知
package com.tobeshrek.test.aop.advice;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* AOP测试通知
* @author 李国豪
* @date:2020年1月13日
*/
public class MyAdvice {
//前置通知
public void before(){
System.out.println("这是前置通知!!");
}
//后置通知(如果出现异常不会调用)
public void afterReturning(){
System.out.println("这是后置通知(如果出现异常不会调用)");
}
//环绕通知
public Object around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("这是环绕通知之前的部分!!");
Object proceed = pjp.proceed();//调用目标方法
System.out.println("这是环绕通知之后的部分!!!");
return proceed;
}
//异常通知
public void afterException(){
System.out.println("这是出现异常提示的通知!!");
}
//后置通知(无论是否出现异常都会调用)
public void after(){
System.out.println("这是后置通知(出现异常也会调用!!)");
}
}
4.配置进行织入,将通知织入目标对象中
<!-- 准备工作:导入aop(约束)命名空间 -->
<!-- 1.配置目标对象 -->
<bean name="userService" class="com.tobeshrek.test.aop.service.impl.UserServiceImpl"></bean>
<!-- 2.配置通知对象 -->
<bean name="myAdvice" class="com.tobeshrek.test.aop.advice.MyAdvice"></bean>
<!-- aop配置 -->
<aop:config>
<!-- 切点 -->
<aop:pointcut expression="execution(* com.tobeshrek.test.aop.service.impl.*ServiceImpl.*(..))" id="pc"/>
<!-- 切面 -->
<aop:aspect ref="myAdvice" >
<!-- 指定名为before方法最为前置通知 -->
<aop:before method="before" pointcut-ref="pc"/>
<!-- 后置通知,出现异常不调用 -->
<aop:after-returning method="afterReturning" pointcut-ref="pc"/>
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="pc" />
<!-- 异常拦截通知 -->
<aop:after-throwing method="afterException" pointcut-ref="pc"/>
<!-- 后置通知,出现异常仍然调用 -->
<aop:after method="after" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
5.测试
//加载spring容器
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); UserService userService = ac.getBean(UserService.class);
//userService.save();//正常的流程
userService.update();//异常的流程
6.结果
- 正常的流程
这是前置通知!!
这是环绕通知之前的部分!!
保存用户!
这是后置通知(出现异常也会调用!!)
这是环绕通知之后的部分!!!
这是后置通知(如果出现异常不会调用)
- 异常的流程
这是前置通知!!
Exception in thread "main" 这是环绕通知之前的部分!!
这是后置通知(出现异常也会调用!!)
这是出现异常提示的通知!!
java.lang.ArithmeticException: / by zero
at com.tobeshrek.test.aop.service.impl.UserServiceImpl.update(UserServiceImpl.java:17)
总结
使用时应该注意:正常执行的话一切都没问题,出现异常的时候环绕通知之后的部分的后置异常不调用通知内的代码不会执行
总结的流程图如下
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于