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");
}
}