【Spring AOP】SpringAOP配置过程——基于XML&&基于注解 && Spring AOP实现原理

概念

  • Spring AOP - Aspect Oriented Programming 面向切面编程
  • AOP的做法是将通用与业务无关的功能抽象封装为切面类
  • 切面可配置在目标方法的执行前、后运行,真正做到即插即用
  • 可以在不修改源码的情况下对程序进行扩展

AOP配置过程——基于XML配置

0. 添加依赖创建配置文件

添加依赖-aspectjweaver

    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.25.RELEASE</version>
    </dependency>

    <!--Spring AOP的底层依赖-->
    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.6</version>
    </dependency>

SpringAOP和AspectJ的关系

  • Eclipse AspectJ,一种基于Java平台的面向切面编程的语言
  • SpringAOP使用AspectJWeaver实现类与方法匹配
  • SpringAOP利用代理模式实现对象运行时功能扩展

创建配置文件: 新增context和aop的xmlns

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    
</beans>

具体的schema可以在spring官网找到,步骤如下:







几个关键概念

1. 实现切面类/方法

  • Aspect,切面,具体的可插拔组件功能类,通常一个切面只实现一个通用功能
  • Target Class/Method:目标类、目标方法,指真正要执行与业务相关的方法

JoinPoint

  • 连接点,切面运行过程中包含了目标类/方法元数据的对象

2. 配置Aspect Bean

3. 定义PointCut

  • PointCut,切入点,使用execution表达式说明切面要作用在系统的哪些类上
  • 使用execution表达式描述切面的作用范围

4. 配置Advice通知

  • Advice,通知,说明具体切面的执行时机,Spring包含了五种不同类型的通知

Around Advice环绕通知

  1. 实现切面类/方法
    ProceedingJoinPoint是JoinPoint的升级版,在原有功能外,还可以控制目标方法是否执行,需要强制返回目标方法返回值
package com.EveX.spring.aop.aspect;

import org.aspectj.lang.ProceedingJoinPoint;

import java.text.SimpleDateFormat;
import java.util.Date;

/*检查程序运行时间的切面类*/
public class MethodChecker {
    public Object check(ProceedingJoinPoint pjp) throws Throwable {
        try {
            long stime = new Date().getTime();  //开始执行时间
            Object ret = pjp.proceed();// 执行目标方法
            long etime = new Date().getTime();  //结束执行时间
            long duration = etime - stime;  //程序执行时长
            if(duration > 1000) {
                String className = pjp.getTarget().getClass().getName();  //获取目标对象的类名
                String methodName = pjp.getSignature().getName();  //获取目标方法名
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss SS");
                String now = dateFormat.format(new Date());
                System.out.println("=====>" + now + ":" + className + "." + methodName + "(" + duration + "ms)<=====");
            }
            return ret;
        } catch (Throwable e) {
            System.out.println("Exception message:" + e.getMessage());
            throw e;
        }

    }
}
  1. 配置Aspect Bean
<bean id="methodChecker" class="com.EveX.spring.aop.aspect.MethodChecker"></bean>
  1. 定义PointCut
  2. 配置Advice通知
    <aop:config>
        <!--定义切入点-->
        <aop:pointcut id="pointcut" expression="execution(* com.EveX..*.*(..))"/>
        <!--定义切面-->
        <aop:aspect ref="methodChecker">
            <!--配置around advice通知-->
            <aop:around method="check" pointcut-ref="pointcut"></aop:around>
        </aop:aspect>
    </aop:config>

AOP配置过程——基于注解配置

  1. 开启context包扫描初始化Ioc容器+启动Spring AOP注解模式
<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
    
    <!--初始化IoC容器-->
    <context:component-scan base-package="com.EveX"></context:component-scan>
    <!--启动Spring AOP注解模式-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
  1. 在切面类中添加注解
package com.EveX.spring.aop.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

/*检查程序运行时间的切面类*/
@Component
@Aspect // 标记当前类是一个切面类
public class MethodChecker {
    /*环绕通知,参数为execution表达式*/
    @Around("execution(* com.EveX..*.*(..))")
    public Object check(ProceedingJoinPoint pjp) throws Throwable {
        try {
            long stime = new Date().getTime();  //开始执行时间
            Object ret = pjp.proceed();// 执行目标方法
            long etime = new Date().getTime();  //结束执行时间
            long duration = etime - stime;  //程序执行时长
            if(duration > 1000) {
                String className = pjp.getTarget().getClass().getName();  //获取目标对象的类名
                String methodName = pjp.getSignature().getName();  //获取目标方法名
                SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss SS");
                String now = dateFormat.format(new Date());
                System.out.println("=====>" + now + ":" + className + "." + methodName + "(" + duration + "ms)<=====");
            }
            return ret;
        } catch (Throwable e) {
            System.out.println("Exception message:" + e.getMessage());
            throw e;
        }

    }
}

Spring AOP实现原理

Spring 基于代理模式实现功能动态扩展,包含两种形式:

  1. 目标类拥有接口,通过JDK动态代理实现功能扩展
  2. 目标类没有接口,通过CGLib组件通过继承的方式实现功能扩展

CGLib实现代理类:

  • CGLib是运行时字节码增强技术
  • AOP会在运行时生成目标继承类字节码的方式进行行为扩展
posted @ 2024-03-01 21:06  沙汀鱼  阅读(29)  评论(0编辑  收藏  举报