写在前面😘
大一电子信息工程新生,请多多关照,希望能在 InfoQ 社区记录自己的学习历程!
【Spring 学习笔记】 系列教程基于 Spring 5.2.10.RELEASE讲解。
一、通知类型
Advice 直译为通知,也有人翻译为 “增强处理”,共有 5 种类型,如下表所示。
二、环境准备
添加 AOP 依赖
在pom.xml文件里添加 Spring AOP 和 AspectJ 的 jar 包依赖
<dependencies> <!--包含Spring AOP:有基本的AOP功能--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> <!--AspectJ框架有更强大的AOP功能--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.5</version> </dependency></dependencies>
复制代码
创建目标接口和实现类
/*UserDao接口*/public interface UserDao { public void save(); public int update();}/*UserDaoImpl实现类*/@Repositorypublic class UserDaoImpl implements UserDao { @Override public void save() { System.out.println("正在执行 UserDao 的 save 方法"); } @Override public int update() { System.out.println("正在执行 UserDao 的 update 方法"); return 1; }}
复制代码
创建通知类
/*通知类*/@Component//将这个类定义成 Bean@Aspect//将这个Bean定义为切面public class MyAdvice { //指定UserDao类中的save方法为切入点 @Pointcut("execution(void com.bighorn.dao.UserDao.save())") private void pt1(){} //指定UserDao类中的update方法为切入点 @Pointcut("execution(int com.bighorn.dao.UserDao.update())") private void pt2(){}}
复制代码
创建 Spring 核心配置类
/*Spring核心配置类*/@Configuration@ComponentScan("com.bighorn") //开启注解扫描@EnableAspectJAutoProxy //开启 AspectJ 的自动代理public class SpringConfig {}
复制代码
编写运行程序
public class App { public static void main(String[] args) throws SQLException { //获取配置类初始化容器 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); //从容器中获取UserDao对象 UserDao userDao = context.getBean(UserDao.class); //调用userDao的方法 userDao.save(); }}
复制代码
三、添加通知
普通通知
在MyAdvice这个通知类中添加前置通知、后置通知、返回后通知、异常后通知及相关注解。
//前置通知@Before("pt1()")public void before() { System.out.println("before advice ...");}//后置通知@After("pt1()")public void after() { System.out.println("after advice ...");}//返回后通知@AfterReturning("pt1()")public void afterReturning() { System.out.println("afterReturning advice ...");}//异常后通知@AfterThrowing("pt1()")public void afterThrowing() { System.out.println("afterThrowing advice ...");}
复制代码
环绕通知(重点)
环绕通知是非常强大的通知,能够完成上述四种通知的所有功能。
/** * 环绕通知需要携带ProceedingJoinPoint类型的参数 * 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法 * 环绕通知必须要有返回值,返回值即为目标方法的返回值 * @param pjp * @return Object */@Around("pt2()")public Object around(ProceedingJoinPoint pjp) { Object result = null; try { System.out.println("这是环绕通知中的前置通知......"); //执行目标方法 result = pjp.proceed(); System.out.println("这是环绕通知中的返回通知......"); } catch (Throwable e) { System.out.println("这是环绕通知中的异常通知......"); } System.out.println("这是环绕通知中的后置通知......"); return result;}
复制代码
修改 App 类,调用 UserDao 的update()方法,运行程序,观察结果。
public class App { public static void main(String[] args) throws SQLException { //获取配置类初始化容器 ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); //从容器中获取UserDao对象 UserDao userDao = context.getBean(UserDao.class); //调用userDao的update方法 userDao.update(); }}
复制代码
运行结果如下👇
注意点
使用环绕通知必须传入形参ProceedingJoinPoint,并使用pjp.proceed()方法实现对原始方法的调用,进而实现原始方法调用前后同时添加通知
通知中如果未使用使用pjp.proceed()方法实现对原始方法的调用,则将跳过原始方法的执行
原始方法的返回值类型决定环绕通知的返回值类型。原始方法若不接收返回值,通知方法的返回值类型可以设置成 void,也可以设置成 Object;如果接收返回值,最好设定为 Object 类型。
由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须要处理 Throwable 异常
写在后面🍻
感谢观看啦✨
有什么不足,欢迎指出哦💖
评论