实现步骤
引入相关依赖
spring-context,aspectjweaver
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<!--junit测试相关-->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
</dependencies>
业务层接口及实现类
//接口
public interface IAccountService {
//接口方法
}
//实现类,并加入相应注解,交由Spring容器管理
@Service("accountService")
public class AccountServiceImpl implements IAccountService {
//实现接口方法
}
通知类(前置通知、后置通知、异常通知、最终通知)
//加入相应注解,交由Spring容器管理
@Component("logger")
//@Aspect表示当前类为切面类
@Aspect
public class Logger {
@Pointcut("execution(* com.mg.service.impl.*.*(..))")
private void pt1(){}
//如果引用上面的方法,可以直接写@Before("execution(* com.mg.service.impl.*.*(..))")
//前置通知
@Before("pt1()")
public void before() {
System.out.println("before");
}
//后置通知
@AfterReturning("pt1()")
public void afterReturning() {
System.out.println("afterReturning");
}
//异常通知
@AfterThrowing("pt1()")
public void afterThrowing() {
System.out.println("afterThrowing");
}
//最终通知
@After("pt1()")
public void after() {
System.out.println("after");
}
//环绕通知
@Around("pt1()")
public Object arroundLog(ProceedingJoinPoint pjp) {
Object val = null;
Object[] args = pjp.getArgs();
try {
System.out.println("前置通知");
val = pjp.proceed(args);
System.out.println("后置通知");
} catch (Throwable throwable) {
System.out.println("异常通知");
throwable.printStackTrace();
}finally {
System.out.println("最终通知");
}
return val;
}
}
注意:Spring基于注解的AOP配置会存在执行调用顺序的问题,所以注解开发时建议使用环绕通知的方式
@Before("pt1()")
引用方法时不要忘记后面的括号 pt1() 另外使用此种方法时注意aspectjweaver的版本问题,如果版本过低会出现java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut pt1 异常,测试时发现低于1.6.6的版本都会出现这个问题
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--配置Spring创建容器时需要扫描的包-->
<context:component-scan base-package="com.mg"></context:component-scan>
<!--配置Spring开启注解AOP的支持-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
测试
@RunWith(SpringJUnit4ClassRunner.class)
//指定配置文件
@ContextConfiguration(locations = "classpath:bean.xml")
public class MyTest {
@Autowired
IAccountService accountService;
@Test
public void test1() {
accountService.saveAccount();
}
}
替换配置文件,使用纯注解方式
@Configuration
@ComponentScan(basePackages = {"com.mg"})
@EnableAspectJAutoProxy
public class SpringConfig { }
测试时注意将配置文件改为配置类:
@RunWith(SpringJUnit4ClassRunner.class)
//配置文件改为配置类
//@ContextConfiguration(locations = "classpath:bean.xml")
@ContextConfiguration(classes = SpringConfig.class)
public class MyTest {
@Autowired
IAccountService accountService;
@Test
public void test1() {
accountService.saveAccount();
}
}