Web技术 —— Spring中的AOP

Posted Putarmor

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Web技术 —— Spring中的AOP相关的知识,希望对你有一定的参考价值。

这里写目录标题

AOP

AOP(Aspect-Oriented Programming):面向切片编程,这是一种编程的思想与编程语言的种类无关,接下来我们主要学习Spring中的AOP。

常见的切面业务有:
1.响应统一的数据格式
2.统一的异常处理
3.统一的日志记录,如跟踪用户访问信息
4.用户统一会话管理、权限管理
5.方法执行时间计算
6.事务的管理
。。。

AOP技术优点:

  • 解决的最大问题就是对横切业务的统一管理;
  • 横切代码的高度复用,和业务代码相互独立;满足了设计上的高内聚低耦合,系统具有更好的扩展性和可维护性。

案例分析

模拟后端的支付业务:

当需要添加日志记录,安全检查和时间统计功能时怎么办呢?
`最简单暴力的方式就是在原类中添加相应的业务,①这会导致类中有大量的重复代码②对原代码具有较大的侵入性

对于问题①,可以把公共部分提出模板或者公共的父类方法,然后让调用的类实现公共模版或者继承的公共的父类。
对于问题②,要求实现类统一继承,这会对实现类的代码造成侵入性,因此在不改变实现类代码的基础上可以通过设计模式来实现。

代理设计模式

静态代理

分为静态代理和动态代理

  • 被代理类:原始类不进行任何修改,在创建和使用时,不再使用原始的被代理类,而是设计一个原始类的代理类;
  • 代理类:基于被代理类,构造一个代理类,使用时也是使用代理类

静态代理设计模式(了解):该设计模式采用两种手段,继承的方式或者聚合+接口的方式

采用继承模式:通过静态代理类去继承原来的类
采用接口模式:
和被代理类一样都实现同一个接口;
在该类构造方法中传入被代理的对象;

动态代理

在class代码运行时期,动态地织入字节码。Spring中的AOP,主要基于两种方式:JDK和CGLIB,这两种方式的代理目标都是被代理类中的方法,在运行期,动态地织入字节码生成代理类。

JDK:Proxy代理对象
CGLIB:是Java的动态代理框架,主要作用就是根据目标类和方法,动态生成代理类;而动态代理框架几乎都是依赖字节码框架(ASM,Javassist等)实现的,字节码框架是直接操作class字节码的框架,它可以加载已有的字节码文件信息,修改部分信息,或者动态生成一个class;

JDK实现(了解):实现InvocationHandler接口重写方法调用处理器,再通过Proxy来创建代理类。
CGLIB:和JDK流程差不多。。。


Spring AOP大部分可以通过CGLIB实现动态代理,当一个类是final class时就必须使用JDK Proxy实现,因为final修饰的类无法被继承

Spring中的AOP

Spring AOP由spring-aop,spring-aspects和spring-instrument三个模块组成。

特点

特点:Spring AOP建立在动态代理的基础上,因此Spring对AOP的支持局限于方法拦截,不能实现属性拦截;但是对于AOP而言,既可以实现属性拦截,也可以实现方法拦截。

Spring AOP的AspectJ支持

SpringAOP只提供了AspectJ的注解语法支持,没有真实使用AspectJ的编译器,在运行时还是基于单纯的AOP;也就是说加入spring-aspects依赖包,只是可以用AspectJ的语法,运行时还是基于spring-aop依赖包的动态实现。

AOP术语

描述切面的常用术语有:通知(advice)、切点(pointcut)、连接点(joinpoint)

切面:由切点和通知组成,它既包含了横切逻辑的定义,也包括了连接点的定义;SpringAOP就是负责实施切面的框架,它将切面所定义的横切逻辑织入到切面所指定的连接点中。

连接点:指在应用执行过程中能够插入切面(Aspect)的一个点。

切点:指通知(advice)所要织入的具体位置。

**通知:**总共有5个

  • 前置通知:使用@before,通知方法会在目标方法调用之前执行
  • 后置通知:使用@after,通知方法会在目标方法返回后或者抛出异常后调用
  • 返回之后通知:使用@AfterReturning,通知方法会在目标方法返回后调用
  • 抛异常后通知:使用@AfterThrowing,通知方法会在目标方法抛出异常后调用
  • 环绕通知:使用@Around,通知包裹了被通知的方法,在被通知的方法通知之前和调用之后执行自定义的行为。

举例:高速公路上的出入口都称为连接点,而某一个我要出的出入口称为切点。

SpringAOP示例

1.先引入spring-aop依赖
2.定义切面(规则)
3.添加通知

被代理类:

package com.example.demo.controller;


import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
public class UserController 

    @RequestMapping("/login")
    public int login(String username, String password)
        System.out.println("进入了login方法。。。");
        return 1;
    

    @RequestMapping("/register")
    public int register(String username, String password)
        System.out.println("进入了register方法。。。");
        return 1;
    

package com.example.demo.pointcut;


import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class UserPointcut 

    //1.定义切面规则
    @Pointcut("execution(* com.example.demo.controller.UserController.*(..))")
    public void pointcut()

    

    //2.添加通知
    @Before("pointcut()")
    public void doBefore()
        System.out.println("执行了前置通知");
    

    @After("pointcut()")
    public void doAfter()
        System.out.println("执行了后置通知");
    

    @AfterReturning("pointcut()")
    public void doReturning()
        System.out.println("执行了返回结果之前的通知方法");
    

    @AfterThrowing("pointcut()")
    public void doThrowing()
        System.out.println("执行了抛出异常之前的通知方法");
    

    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint)
        System.out.println("进入了环绕通知:方法执行之前");
        Object ret = null;
        try 
            //执行被代理的方法
            ret = joinPoint.proceed();
         catch (Throwable throwable) 
            throwable.printStackTrace();
        
        System.out.println("执行了环绕通知:方法执行之后");
        return ret;
    

当我们访问user/login路由后:


Spring的AOP和拦截器的区别:
拦截器的拦截粒度比较粗,而Spring的AOP拦截粒度更细。

织入

织入是把切面应用到目标对象并创建新的代理对象的过程,切面在指定的连接点被织入到目标对象中,在目标对象的生命周期里有多个点可以织入。

织入时机:类加载时期、编译期、运行期。

目标对象
目标对象(Target Object):被一个或者多个切面所通知的对象,也把它叫做被通知的对象,因为SpringAOP是通过运行时代理实现的,所以这个对象永远是一个被代理的(Proxied)对象。

以上是关于Web技术 —— Spring中的AOP的主要内容,如果未能解决你的问题,请参考以下文章

Web技术 —— Spring中的AOP

Spring技术内幕:Spring AOP的实现原理

SpringMVC中配aop拦截不生效,咋回事

Spring Boot中使用AOP统一处理Web请求日志

Spring Boot中使用AOP统一处理Web请求日志

Spring Boot中使用AOP统一处理Web请求日志