Spring整合AspectJ基于注解实现AOP
我们把上一篇Spring整合AspectJ基于XML实现AOP进行改造成基于注解实现。
首先是pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.cc.study</groupId>
<artifactId>spring-study</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- 4个核心(beans、core、context、expression) -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
替换bean
<!-- 1 创建目标类 -->
<bean id="userServiceId" class="com.cc.study.aspectj.UserServiceImpl"></bean>
<!-- 2 创建切面类(通知) -->
<bean id="myAspectId" class="com.cc.study.aspectj.MyAspect"></bean>
- MyAspect
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;
/**
* 切面类,含有多个通知
*/
@Component
public class MyAspect {
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知 : " + joinPoint.getSignature().getName());
}
public void myAfterReturning(JoinPoint joinPoint,Object ret){
System.out.println("后置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
}
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("前");
//手动执行目标方法
Object obj = joinPoint.proceed();
System.out.println("后");
return obj;
}
public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("抛出异常通知 : " + e.getMessage());
}
public void myAfter(JoinPoint joinPoint){
System.out.println("最终通知");
}
}
- UserServiceImpl
@Service("userServiceId")
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("addUser()");
}
@Override
public void updateUser() {
// int i = 1 / 0;
System.out.println("updateUser()");
}
@Override
public void deleteUser() {
System.out.println("deleteUser()");
}
}
然后我们配置要开启扫描注解
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 1.扫描 注解类 -->
<context:component-scan base-package="com.cc.study.aspectj.annotation"></context:component-scan>
</beans>
替换AOP
- 必须进行aspectj 自动代理
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 1.扫描 注解类 -->
<context:component-scan base-package="com.cc.study.aspectj.annotation"></context:component-scan>
<!-- 2.确定 aop注解生效 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
声明切面
原先我们是在xml中进行配置
<bean id="myAspectId" class="com.cc.study.aspectj.MyAspect"></bean>
现在我们利用注解@Aspect进行配置
/**
* 切面类,含有多个通知
*/
@Component
@Aspect
public class MyAspect {
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知 : " + joinPoint.getSignature().getName());
}
public void myAfterReturning(JoinPoint joinPoint,Object ret){
System.out.println("后置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
}
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("前");
//手动执行目标方法
Object obj = joinPoint.proceed();
System.out.println("后");
return obj;
}
public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("抛出异常通知 : " + e.getMessage());
}
public void myAfter(JoinPoint joinPoint){
System.out.println("最终通知");
}
}
替换前置通知
之前我们在XML中可以这么配置
<aop:before method="myBefore" pointcut="execution(* com.cc.study.aspectj.UserServiceImpl.*(..))"/>
或者
<aop:pointcut expression="execution(* com.cc.study.aspectj.UserServiceImpl.*(..))" id="myPointCut"/>
<aop:before method="myBefore" pointcut-ref="myPointCut"/>
现在我们利用注解@Before配置MyAspect类
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
/**
* 切面类,含有多个通知
*/
@Component
@Aspect
public class MyAspect {
//切入点当前有效
@Before("execution(* com.cc.study.aspectj.annotation.UserServiceImpl.*(..))")
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知 : " + joinPoint.getSignature().getName());
}
public void myAfterReturning(JoinPoint joinPoint,Object ret){
System.out.println("后置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
}
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("前");
//手动执行目标方法
Object obj = joinPoint.proceed();
System.out.println("后");
return obj;
}
public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("抛出异常通知 : " + e.getMessage());
}
public void myAfter(JoinPoint joinPoint){
System.out.println("最终通知");
}
}
测试
@Test
public void demo01(){
String xmlPath = "aspectj2.xml";
AbstractApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
UserService userService = (UserService) applicationContext.getBean("userServiceId");
userService.addUser();
userService.updateUser();
userService.deleteUser();
}
替换公共切入点
相当于我们在XML中配置的:
<aop:pointcut expression="execution(* com.cc.study.aspectj.UserServiceImpl.*(..))" id="myPointCut"/>
<aop:before method="myBefore" pointcut-ref="myPointCut"/>
替代<aop:pointcut expression="execution(* com.cc.study.aspectj.UserServiceImpl.*(..))" id="myPointCut"/>
这一部分
我们利用注解@Pointcut进行替换
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* 切面类,含有多个通知
*/
@Component
@Aspect
public class MyAspect {
//切入点当前有效
@Before("execution(* com.cc.study.aspectj.annotation.UserServiceImpl.*(..))")
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知 : " + joinPoint.getSignature().getName());
}
public void myAfterReturning(JoinPoint joinPoint,Object ret){
System.out.println("后置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
}
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("前");
//手动执行目标方法
Object obj = joinPoint.proceed();
System.out.println("后");
return obj;
}
public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("抛出异常通知 : " + e.getMessage());
}
public void myAfter(JoinPoint joinPoint){
System.out.println("最终通知");
}
//声明公共切入点
@Pointcut("execution(* com.cc.study.aspectj.annotation.UserServiceImpl.*(..))")
private void myPointCut(){
}
}
替换后置
之前我们在xml中是如下配置
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" />
然后我们可以利用如下注解进行替换,这里使用value=“myPointCut()”,来指定我们上面配置的公共切入点
@AfterReturning(value="myPointCut()" ,returning="ret")
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
* 切面类,含有多个通知
*/
@Component
@Aspect
public class MyAspect {
//切入点当前有效
@Before("execution(* com.cc.study.aspectj.annotation.UserServiceImpl.*(..))")
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知 : " + joinPoint.getSignature().getName());
}
@AfterReturning(value="myPointCut()" ,returning="ret")
public void myAfterReturning(JoinPoint joinPoint,Object ret){
System.out.println("后置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
}
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("前");
//手动执行目标方法
Object obj = joinPoint.proceed();
System.out.println("后");
return obj;
}
public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("抛出异常通知 : " + e.getMessage());
}
public void myAfter(JoinPoint joinPoint){
System.out.println("最终通知");
}
//声明公共切入点
@Pointcut("execution(* com.cc.study.aspectj.annotation.UserServiceImpl.*(..))")
private void myPointCut(){
}
}
测试:
替换环绕
<aop:around method="myAround" pointcut-ref="myPointCut"/>
可以利用注解@Around(value = “myPointCut()”)进行替换
/**
* 切面类,含有多个通知
*/
@Component
@Aspect
public class MyAspect {
//切入点当前有效
// @Before("execution(* com.cc.study.aspectj.annotation.UserServiceImpl.*(..))")
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知 : " + joinPoint.getSignature().getName());
}
//@AfterReturning(value="myPointCut()" ,returning="ret")
public void myAfterReturning(JoinPoint joinPoint,Object ret){
System.out.println("后置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
}
@Around(value = "myPointCut()")
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("前");
//手动执行目标方法
Object obj = joinPoint.proceed();
System.out.println("后");
return obj;
}
public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("抛出异常通知 : " + e.getMessage());
}
public void myAfter(JoinPoint joinPoint){
System.out.println("最终通知");
}
//声明公共切入点
@Pointcut("execution(* com.cc.study.aspectj.annotation.UserServiceImpl.*(..))")
private void myPointCut(){
}
}
把其他的注解进行注释掉测试
替换抛出异常
<aop:after-throwing method="myAfterThrowing" pointcut="execution(*com.cc.study.aspectj.annotation.UserServiceImpl.*(..))" throwing="e"/>
利用注解@AfterThrowing进行替换
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* 切面类,含有多个通知
*/
@Component
@Aspect
public class MyAspect {
//切入点当前有效
// @Before("execution(* com.cc.study.aspectj.annotation.UserServiceImpl.*(..))")
public void myBefore(JoinPoint joinPoint){
System.out.println("前置通知 : " + joinPoint.getSignature().getName());
}
// @AfterReturning(value="myPointCut()" ,returning="ret")
public void myAfterReturning(JoinPoint joinPoint,Object ret){
System.out.println("后置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
}
// @Around(value = "myPointCut()")
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("前");
//手动执行目标方法
Object obj = joinPoint.proceed();
System.out.println("后");
return obj;
}
@AfterThrowing(value="execution(* com.cc.study.aspectj.annotation.UserServiceImpl.*(..))" ,throwing="e")
public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
System.out.println("抛出异常通知 : " + e.getMessage());
}
public void myAfter(JoinPoint joinPoint){
System.out.println("最终通知");
}
//声明公共切入点
@Pointcut("execution(* com.cc.study.aspectj.annotation.UserServiceImpl.*(..))")
private void myPointCut(){
}
}
测试
@Override
public void updateUser() {
int i = 1 / 0;
System.out.println("updateUser()");
}
AOP注解总结
- @Aspect 声明切面,修饰切面类,从而获得 通知。
- 通知
- @Before 前置
- @AfterReturning 后置
- @Around 环绕
- @AfterThrowing 抛出异常
- @After 最终
- 切入点
@PointCut ,修饰方法 private void xxx(){} 之后通过“方法名”获得切入点引用