利用AOP可以对业务逻辑的各个部分进行隔离,从而使得各部分之间的耦合度降低。
Spring框架一般都是基于AspectJ实现AOP操作。
1. AOP中的术语
(1)连接点:类中可以被增强的方法;
(2)切入点:类中实际被增强的方法;
(3)通知(增强):给类中某个方法编写的实际增强的逻辑部分;通知有多种类型:①前置通知、②后置通知、③环绕通知、④异常通知、⑤最终通知
(4)切面:把通知应用到切入点的过程
2. 切入点表达式
切入点表达式的作用:指明对哪个类里的哪个方法进行增强
语法结构:execution( [权限修饰符] [返回值类型] [类的全类名] [方法名称] ([参数列表]) )
例1. 对server.dao下的UserDao类里的add方法进行增强:execution(public void server.dao.Userdao.add(..));可以将public写成*,则为所有权限;可以去掉返回值类型。
例2. 对server.dao下的UserDao类里的所有方法进行增强:execution(* server.dao.Userdao.*(..))。
例3. 对server.dao下的所有类里的所有方法进行增强:execution(* server.dao.*.*(..))。
一. 使用注解方式通过AspectJ实现AOP
1. 引入AspectJ依赖
在pom.xml中引入AspectJ的相关依赖
<!--AspectJ 开始-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.3.19</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.9.5</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.0</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
<!--AspectJ 结束-->
2. 创建类
package aop;
import org.springframework.stereotype.Component;
@Component
public class User { //被增强的类
public void add() {
System.out.println("add");
}
public void update(){
System.out.println("update");
}
}
3. 创建增强类并配置不同类型的通知
需要在创建的增强类上添加注解@Aspect来生成代理对象,并在增强类中使用切入点表达式来配置被增强的方法。
package aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component //创建类
@Aspect //生成代理对象
public class UserProxy { //增强User的类
//@Before:前置通知 --> 在被增强方法前执行
@Before(value = "execution(* aop.User.add(..))")
public void beforeUserMethod(){
System.out.println("before.......");
}
//@After:后置通知 --> 在被增强方法被调用后执行
@After(value = "execution(* aop.User.add(..))")
public void afterUserMethod(){
System.out.println("after.......");
}
//@AfterReturning:后置通知 --> 在被增强方法返回结果后执行
@AfterReturning(value = "execution(* aop.User.add(..))")
public void afterReturningUserMethod(){
System.out.println("afterReturning.......");
}
//@AfterThrowing:异常通知(当被增强的方法内部有异常时执行)
@AfterThrowing(value = "execution(* aop.User.add(..))")
public void afterThrowingUserMethod(){
System.out.println("afterThrowing.......");
}
//@Around环绕通知:在被增强方法前后都执行
@Around(value = "execution(* aop.User.add(..))")
public void AroundUserMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕之前");
//执行被增强的方法
proceedingJoinPoint.proceed();
System.out.println("环绕之后");
}
}
4. 在配置文件中引入名称空间、开启注解扫描、开启Aspect生成代理对象
<?xml version="1.0" encoding="UTF-8"?>
<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/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">
<!--开启注解扫描-->
<context:component-scan base-package="aop"></context:component-scan>
<!--开启Aspect生成代理对象-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
5.测试
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import aop.User;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testSpring {
@Test
public void test() {
//加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
User user = context.getBean(User.class);
user.add();
//被增强方法中没有错误时会输出以下内容: 被增强方法中有错误时会输出以下内容:
//环绕之前 环绕之前
//before....... before.......
//add afterThrowing.......
//afterReturning....... after.......
//after.......
//环绕之后
}
}
二. 优化
1. 可以抽取相同的切入点
package aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component //创建类
@Aspect //生成代理对象
public class UserProxy { //增强User的类
//抽取相同切入点
@Pointcut(value = "execution(* aop.User.add(..))")
public void point(){
}
//@Before:前置通知 --> 在被增强方法前执行
@Before(value = "point()")
public void beforeUserMethod(){
System.out.println("before.......");
}
//@After:后置通知 --> 在被增强方法被调用后执行
@After(value = "point()")
public void afterUserMethod(){
System.out.println("after.......");
}
//@AfterReturning:后置通知 --> 在被增强方法返回结果后执行
@AfterReturning(value = "point()")
public void afterReturningUserMethod(){
System.out.println("afterReturning.......");
}
//@AfterThrowing:异常通知(当被增强的方法内部有异常时执行)
@AfterThrowing(value = "point()")
public void afterThrowingUserMethod(){
System.out.println("afterThrowing.......");
}
//@Around环绕通知:在被增强方法前后都执行
@Around(value = "point()")
public void AroundUserMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕之前");
//执行被增强的方法
proceedingJoinPoint.proceed();
System.out.println("环绕之后");
}
}
2. 多个增强类对同一个类进行增强,可以通过使用@Order来设置增强类的优先级,@Order()中的值越小,优先级越高
package aop;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Aspect
@Order(1)
public class PersonProxy {
@Before(value = "execution(* aop.User.add(..))")
public void beforeUserMethod(){
System.out.println("Person before.......");
}
}
package aop;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component //创建类
@Aspect //生成代理对象
@Order(2)
public class UserProxy { //增强User的类
//抽取相同切入点
@Pointcut(value = "execution(* aop.User.add(..))")
public void point(){
}
//@Before:前置通知 --> 在被增强方法前执行
@Before(value = "point()")
public void beforeUserMethod(){
System.out.println("before.......");
}
//@After:后置通知 --> 在被增强方法被调用后执行
@After(value = "point()")
public void afterUserMethod(){
System.out.println("after.......");
}
//@AfterReturning:后置通知 --> 在被增强方法返回结果后执行
@AfterReturning(value = "point()")
public void afterReturningUserMethod(){
System.out.println("afterReturning.......");
}
//@AfterThrowing:异常通知(当被增强的方法内部有异常时执行)
@AfterThrowing(value = "point()")
public void afterThrowingUserMethod(){
System.out.println("afterThrowing.......");
}
//@Around环绕通知:在被增强方法前后都执行
@Around(value = "point()")
public void AroundUserMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕之前");
//执行被增强的方法
proceedingJoinPoint.proceed();
System.out.println("环绕之后");
}
}
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import aop.User;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class testSpring {
@Test
public void test() {
//加载配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("config.xml");
User user = context.getBean(User.class);
user.add();
//Person before.......
//环绕之前
//before.......
//add
//afterReturning.......
//after.......
//环绕之后
}
}