深入理解 Spring AOP:解析面向切面编程的利器!

大家好,我是香香。

昨天我们介绍了 Spring 两大核心特性中的 IOC(控制反转),今天我们来介绍另一个核心特性 AOP(面向切面编程)。

AOP(面向切面编程)

在软件开发领域,我们经常会遇到一些横切关注点(的问题,比如日志记录、事务管理、安全性等。

这些问题往往涉及多个模块,而且与业务逻辑相互交织,给代码的维护和扩展带来了困难。

为了解决上述问题,Spring 框架提供了一个强大的工具—— AOP。

1. 什么是 AOP?

AOP 是一种编程范式,它允许开发者将关注点分离出来,并将其应用于不同的对象上。

在 Spring 中,AOP 通过切面(Aspect)和连接点(Join Point)的概念来实现。 切面定义了横切关注点的行为,而连接点则是程序执行过程中能够被切面拦截的特定点。

通过将切面与连接点结合起来,我们可以实现对关注点的统一处理,而无需修改原始业务逻辑代码。

2. Spring中的AOP实现方式

在 Spring 中,AOP 的实现主要依赖于动态代理技术。

Spring AOP 提供了两种代理方式:基于接口的代理(JDK动态代理)和基于类的代理(CGLIB动态代理)。

当目标对象实现了接口时,Spring 会使用JDK动态代理;否则,将使用 CGLIB 动态代理。

3. AOP的核心概念

  1. 切面(Aspect):切面是定义横切关注点以及它们的行为的类。它由切点和通知组成。
  2. 切点(Pointcut):切点是一个表达式,用于匹配连接点。通过使用切点表达式,我们可以指定需要拦截的特定方法或类。
  3. 通知(Advice):通知定义了在切点处执行的具体操作。Spring 提供了几种常见的通知类型,包括前置通知、后置通知、异常通知、环绕通知等。
  4. 连接点(Join Point):连接点是程序执行过程中能够被切面拦截的特定点。在 Spring 中,连接点可以是方法的调用、方法的执行、异常的抛出等。
  5. 织入(Weaving):织入是将切面应用到目标对象上的过程。Spring 支持编译时织入、类加载时织入和运行时织入三种方式。

4. 使用Spring AOP的步骤

  1. 引入 Spring 框架和 AOP 相关的依赖。
  2. 创建切面类,定义切点和通知。
  3. 配置 AOP,在 Spring 配置文件中声明切面和目标对象。
  4. 测试 AOP,执行目标方法,观察切面是否生效。

5. Spring AOP的应用场景

  1. 日志记录:通过 AOP 可以方便地实现日志记录功能,无需修改原始业务逻辑代码。
  2. 事务管理:AOP 可以在方法执行前后添加事务的开启和提交操作,简化了事务管理的代码。
  3. 安全性控制:通过 AOP 可以实现权限校验、加密解密等安全性控制的功能。
  4. 性能监控:通过 AOP 可以监控方法的执行时间、资源占用情况等,用于性能优化和瓶颈定位。

6. AOP 操作(基于 AspectJ 注解)

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

6. 总结

通过对Spring AOP的详细解析,我们了解到AOP是一种强大的编程范式,能够有效地解决横切关注点的问题。在Spring框架中,AOP通过切面、连接点、通知等概念实现了对关注点的统一处理。我们可以利用AOP实现日志记录、事务管理、安全性控制等功能,提高代码的可维护性和可扩展性。

你可能感兴趣的:(Spring,spring,java)