大家好,我是香香。
昨天我们介绍了 Spring 两大核心特性中的 IOC(控制反转),今天我们来介绍另一个核心特性 AOP(面向切面编程)。
在软件开发领域,我们经常会遇到一些横切关注点(的问题,比如日志记录、事务管理、安全性等。
这些问题往往涉及多个模块,而且与业务逻辑相互交织,给代码的维护和扩展带来了困难。
为了解决上述问题,Spring 框架提供了一个强大的工具—— AOP。
AOP 是一种编程范式,它允许开发者将关注点分离出来,并将其应用于不同的对象上。
在 Spring 中,AOP 通过切面(Aspect)和连接点(Join Point)的概念来实现。 切面定义了横切关注点的行为,而连接点则是程序执行过程中能够被切面拦截的特定点。
通过将切面与连接点结合起来,我们可以实现对关注点的统一处理,而无需修改原始业务逻辑代码。
在 Spring 中,AOP 的实现主要依赖于动态代理技术。
Spring AOP 提供了两种代理方式:基于接口的代理
(JDK动态代理)和基于类的代理
(CGLIB动态代理)。
当目标对象实现了接口时,Spring 会使用JDK动态代理;否则,将使用 CGLIB 动态代理。
1、「什么是AspectJ ?」
Spring 框架一般都是基于 AspectJ 实现 AOP 操作。AspectJ 不是 Spring 组成部分,独立 AOP 框架,一般把 AspectJ 和 Spring 框架一起使用,进行 AOP 操作。
2、「基于AspectJ实现AOP操作」
(1)基于xml配置文件实现
(2)基于注解方式实现(使用)
3、「在项目工程里面引入AOP相关依赖」
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
<version>5.2.15.RELEASEversion>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>1.9.9version>
dependency>
<dependency>
<groupId>aopalliancegroupId>
<artifactId>aopallianceartifactId>
<version>1.0version>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjtoolsartifactId>
<version>1.9.9version>
dependency>
<dependency>
<groupId>cglibgroupId>
<artifactId>cglibartifactId>
<version>3.3.0version>
dependency>
4、「切入点表达式」
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构:
execution (【权限修饰符】【返回类型】【类全路径】【方法名称】(【参数列表】))
举例1:对com.jin.dao.UserDao类里面的add进行增强。
execution(* com.jin.dao.*.*(..))
举例2:对com.jin.dao.UserDao类里面的所有的方法进行增强。
execution(* com.jin.dao.UserDao.*(..))
举例3:对com.jin.dao类里面所有类,类里面的所有的方法进行增强。
execution(* com.jin.dao.*.*(..))
1、创建类,在类里面定义方法
//被增强的类
public class User {
public void add(){
System.out.println("add ...");
}
2、创建增强类(编写增强逻辑)
(1)在增强类里面,创建方法,让不同方法代表不同通知类型
//增强类
public class UserProxy {
//前置通知
public void before(){
System.out.println("before ...");
}
}
3、进行通知的配置
(1)在spring配置文件中,开启注解扫描
<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="com.jin.aopanno">context:component-scan>
beans>
(2)使用注解创建User和UserProxy对象
//被增强的类
@Component
public class User {
...
}
//增强类
@Component
public class UserProxy {
...
}
(3)在增强类上面添加注解@Aspect
//增强类
@Component
@Aspect //生成代理对象
public class UserProxy {
...
}
(4)在spring配置文件中开启生成代理对象
<aop:aspectj-autoproxy>aop:aspectj-autoproxy>
4、配置不同类型的通知
(1)在增加类的里面,通知方法上面添加通知类型注解,使用切入点表达式配置
//增强类
@Component
@Aspect //生成代理对象
public class UserProxy {
//前置通知
//@Before注解表示作为前置通知
@Before(value = "execution(* com.jin.aopanno.User.add(..))")
public void before(){
System.out.println("before ...");
}
@AfterReturning(value = "execution(* com.jin.aopanno.User.add(..))")
public void afterReturning(){
System.out.println("afterReturning ...");
}
@After(value = "execution(* com.jin.aopanno.User.add(..))")
public void after(){
System.out.println("after ...");
}
@AfterThrowing(value = "execution(* com.jin.aopanno.User.add(..))")
public void afterThrowing(){
System.out.println("AfterThrowing ...");
}
@Around(value = "execution(* com.jin.aopanno.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕之前 ...");
proceedingJoinPoint.proceed();
System.out.println("环绕之后 ...");
}
}
5、相同的切入点抽取
//增强类
@Component
@Aspect //生成代理对象
public class UserProxy {
//相同切入点抽取
@Pointcut(value = "execution(* com.jin.aopanno.User.add(..))")
public void pointdemo(){}
//前置通知
//@Before注解表示作为前置通知
@Before(value = "pointdemo()")
public void before(){
System.out.println("before ...");
}
}
6、有多个增强类多同一个方法进行增强,设置增强类优先级
(1)在增强类撒谎给你面添加注解@Order(数字类型值),数字类型值越小优先级越高
@Component
@Aspect //生成代理对象
@Order(1) //优先级(数字值越小优先级越高)
public class PersonProxy {
...
}
7、完全使用注解开发
(1)创建配置类,不需要创建xml配置文件
@ComponentScan(basePackages = {"com.jin.pojo"})
@Configuration
@EnableAspectJAutoProxy(proxyTargetClass = true) //默认EnableAspectJAutoProxy为false
public class SpringConfig {
}
(2)测试代码
@Test
public void MyTest01(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
User user = context.getBean("user", User.class);
user.add();
}
通过对Spring AOP的详细解析,我们了解到AOP是一种强大的编程范式,能够有效地解决横切关注点的问题。在Spring框架中,AOP通过切面、连接点、通知等概念实现了对关注点的统一处理。我们可以利用AOP实现日志记录、事务管理、安全性控制等功能,提高代码的可维护性和可扩展性。