Spring AOP基于注解的配置,原理跟上篇写的基于xml配置的一样,只是换一种配置方法,注解的方式有时候比xml的方式更容易读懂,加上后面学习的Spring boot,大多都是基于注解形式的配置。
- 首先,还是导包,需要导入(Maven导包)
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>4.3.20.RELEASE</version> </dependency>
- 编写需要增强的类UserServiceImpl
package com.springday.service; public interface UserService { public void save(); public void delete(); public void update(); public void find(); }
package com.springday.service; public class UserServiceImpl implements UserService { @Override public void save() { System.out.println("保存操作"); } @Override public void delete() { System.out.println("删除操作"); } @Override public void update() { System.out.println("更新操作"); } @Override public void find() { System.out.println("查找操作"); } }
- 在Spring的主配置文件applicationContext.xml开启使用AOP注解配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd"> <!-- 导入AOP(约束)命名空间 --> <!-- 1、配置目标对象 --> <bean name="userServiceTarget" class="com.springday.service.UserServiceImpl"></bean> <!-- 2、配置通知对象 --> <bean name="myAdvice" class="com.springday.annotation.MyAdvice"></bean> <!-- 3、开启使用注解完成织入 --> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
-
基于注解配置通知类MyAdvice
package com.springday.annotation; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; //通知类 @Aspect //表示该类是一个通知类 public class MyAdvice { //前置通知 // |-目标方法运行之前调用 //后置通知(如果出现异常不会调用) // |-在目标方法运行之后调用 //环绕通知 // |-在目标方法之前和之后都调用 //异常拦截通知 // |-如果出现异常,就会调用 //后置通知(无论是否出现 异常都会调用) // |-在目标方法运行之后调用 //---------------------------------------------------------------- //前置通知 //指定该方法是前置通知,并且制定切入点 @Before("execution(* com.springday.service..*Service.*(..))") public void before(){ System.out.println("这是前置通知!!"); } //后置通知 @AfterReturning("execution(* com.springday.service..*Service.*(..))") public void afterReturning(){ System.out.println("这是后置通知(如果出现异常不会调用)!!"); } //环绕通知 @Around("execution(* com.springday.service..*Service.*(..))") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("这是环绕通知之前的部分!!"); Object proceed = pjp.proceed();//调用目标方法 System.out.println("这是环绕通知之后的部分!!"); return proceed; } //异常通知 @AfterThrowing("execution(* com.springday.service..*Service.*(..))") public void afterException(){ System.out.println("出事啦!出现异常了!!"); } //后置通知 @After("execution(* com.springday.service..*Service.*(..))") public void after(){ System.out.println("这是后置通知(出现异常也会调用)!!"); } }
如果切入点一样的话,也可以这么写
package com.springday.annotation; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; //通知类 @Aspect //表示该类是一个通知类 public class MyAdvice { @Pointcut("execution(* com.springday.service..*Service.*(..))") public void pc() {} //指定该方法是前置通知,并且制定切入点 @Before("MyAdvice.pc()") public void before(){ System.out.println("这是前置通知!!"); } //后置通知 @AfterReturning("MyAdvice.pc()") public void afterReturning(){ System.out.println("这是后置通知(如果出现异常不会调用)!!"); } //环绕通知 @Around("MyAdvice.pc()") public Object around(ProceedingJoinPoint pjp) throws Throwable { System.out.println("这是环绕通知之前的部分!!"); Object proceed = pjp.proceed();//调用目标方法 System.out.println("这是环绕通知之后的部分!!"); return proceed; } //异常通知 @AfterThrowing("MyAdvice.pc()") public void afterException(){ System.out.println("出事啦!出现异常了!!"); } //后置通知 @After("MyAdvice.pc()") public void after(){ System.out.println("这是后置通知(出现异常也会调用)!!"); } }
-
编写测试类进行测试
package com.springday.annotation; import javax.annotation.Resource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.springday.service.UserService; //创建容器 @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:com/springday/annotation/applicationContext.xml") public class Demo { @Resource(name="userServiceTarget") private UserService us; @Test //测试注解 public void fun1() { us.find(); } }
-
运行结果