Spring框架一般是基于AspectJ实现AOP操作
什么是AspectJ?
AspectJ是独立的框架,可以和Spring一起用,完成Spring AOP的操作。
基于AspectJ实现Spring AOP具体实现方式分为两种:
基于XML配置文件
基于注解方式
实现具体操作前的准备工作:
1)环境搭建,引入相关依赖
<!-- spring-aop--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.2.8.RELEASE</version> </dependency> <dependency> <groupId>net.sourceforge.cglib</groupId> <artifactId>com.springsource.net.sf.cglib</artifactId> <version>2.2.0</version> </dependency> <dependency> <groupId>aopalliance</groupId> <artifactId>aopalliance</artifactId> <version>1.0</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.2</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.2.8.RELEASE</version> </dependency>
基于注解方式实现AOP的具体操作
开启注解扫描和开启Aspect生成代理对象
package org.learn.spring5.config; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.EnableAspectJAutoProxy; //Configuration,让Spring知道这是个配置类 @Configuration @ComponentScan(basePackages = {"org.learn.spring5"}) @EnableAspectJAutoProxy public class SpringConfig { }2.创建类,在类里定义方法,并通过注解的方式完成对象的创建。
package org.learn.spring5.service.impl; import org.learn.spring5.service.UserService; import org.springframework.stereotype.Service; @Service //1 public class UserServiceImpl implements UserService { //2 public void add() { System.out.println("add"); } public void del() { System.out.println("del"); } public void update() { System.out.println("update"); } public void query() { System.out.println("query"); } }3.对类中的方法进行增强:
1)创建一个增强的类
2)实现增强的逻辑
3)并通过注解的方式完成该对象的创建
4)添加通知的注解配置@Aspect
5)配置不同类型的通知,在增强的类中,在作为通知方法上面增加通知类型注解,使用切入点表达式配置
具体代码如下:
package org.learn.spring5.service.impl; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.stereotype.Component; //增强类,编写增强的方法 @Component //(3) @Aspect //(4) public class UserServiceProxy { //(1) //前置通知 @Before(value ="execution(* org.learn.spring5.service.impl.UserServiceImpl.add(..))") //(5) public void before(){ System.out.println("before"); //(2) } //后置通知 @After(value ="execution(* org.learn.spring5.service.impl.UserServiceImpl.add(..))") public void after(){ System.out.println("After"); } //最终通知 @AfterReturning(value ="execution(* org.learn.spring5.service.impl.UserServiceImpl.add(..))") public void afterReturning(){ System.out.println("afterReturning"); } //异常通知 @AfterThrowing(value ="execution(* org.learn.spring5.service.impl.UserServiceImpl.add(..))") public void afterThrowing(){ System.out.println("AfterThrowing"); } //环绕通知 @Around(value ="execution(* org.learn.spring5.service.impl.UserServiceImpl.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint){ System.out.println("环绕之前"); try { proceedingJoinPoint.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); } System.out.println("环绕之后"); } }4. 测试类编写:
import org.junit.Test; import org.learn.spring5.config.SpringConfig; import org.learn.spring5.service.UserService; import org.learn.spring5.service.impl.UserServiceImpl; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class TestSpring5 { /** * Spring AOP实现 */ @Test public void test1(){ AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class); UserService userService = context.getBean("userServiceImpl", UserService.class); userService.add(); } }对公共切入点抽取
例如上面的例子,5种切入点表达式切入的都是同一个方法,表达式都是一样的,那么如何将这行代码抽取成公共的代码进行调用呢?
package org.learn.spring5.service.impl; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; //增强类,编写增强的方法 @Component @Aspect public class UserServiceProxy { //相同的切入点抽取 @Pointcut(value = "execution(* org.learn.spring5.service.impl.UserServiceImpl.add(..))") public void pointCunt(){ } //前置通知 @Before(value = "pointCunt()") public void before(){ System.out.println("before"); } //后置通知 @After(value = "pointCunt()") public void after(){ System.out.println("After"); } //最终通知 @AfterReturning(value = "pointCunt()") public void afterReturning(){ System.out.println("afterReturning"); } //异常通知 @AfterThrowing(value = "pointCunt()") public void afterThrowing(){ System.out.println("AfterThrowing"); } //环绕通知 @Around(value = "pointCunt()") public void around(ProceedingJoinPoint proceedingJoinPoint){ System.out.println("环绕之前"); try { proceedingJoinPoint.proceed(); } catch (Throwable throwable) { throwable.printStackTrace(); } System.out.println("环绕之后"); } }一个方法有多个增强类,设置优先级可以确定执行的顺序
@order()注解,括号里的值越小,优先级越高,先执行
package org.learn.spring5.service.impl; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; //增强类2 @Component @Aspect @Order(3) public class UserServiceProxy2 { @Before(value ="execution(* org.learn.spring5.service.impl.UserServiceImpl.add(..))") public void before(){ System.out.println("增强类2 before"); } }