Spring-AOP

简介: Spring-AOP

一、使用场景(横切问题关注点)

  • 日志记录
  • 异常处理
  • 权限验证
  • 缓存处理
  • 事物处理
  • 数据持久化
  • 效率检查
  • 内容分发


二、AOP中主要概念相关理解(切面)


  • aspect:切面,切面有切点和通知组成,即包括横切逻辑的定义也包括连接点的定义
  • pointcut:切点,每个类都拥有多个连接点,可以理解是连接点的集合
  • joinpoint:连接点,程s序执行的某个特定位置,如某个方法调用前后等
  • weaving:织出,将增加的目标类的具体连接点的过程
  • advice:通知,是织入到目标类连接点上的一段代码,就是增加到什么地方?增加什么内容?
  • target:目标对象,通知织入的目标类
  • aop Proxy:代理对象,即增加后产生的对象


Spring AOP 底层实现,是通过JDK动态代理或CGLib代理在运行时期在对象初始化阶段织入代码的。



JDK动态代理基于接口实现     --- 区别 ---    CGLib是基于类的继承实现的


三、Aspect概念(通知的种类)


  1. 1.Before advice
  • 前置通知,即在目标方法调用之前执行。注意:无论方法是否遇到异常都执行
  1. 2.After returning advice
  • 后置通知,在目标方法执行之后执行,前提是目标方法没有遇到异常,如果有异常则不会执行通知。
  1. 3.After Throwing advice
  • 异常通知,在目标方法抛出异常时执行,可以获取异常信息。
  1. 4.After finally advice
  • 最终通知,在目标方法执行后执行,无论是否有异常执行
  1. 5.Around advice
  • 环绕通知,最强大的通知类型,可以控制目标方法的执行(通过调用ProceedingJoinpoint.proceed())可以在目标全过程中进行执行。


四、@Aspect驱动(实现步骤)


  1. 1.定义一个切面类Aspect
  • 即在声明的类,増加@Component @Aspect。两个注解,Springboot项目中要引入 spring- boot- stater-aop依赖包,
  1. 2.定义切点Pointcut
  • 定义切点,并定义切点在那些地方执行,采用@Pointcut注解完成, 如:
@Pointcut( public * com.xxxx.*.*(..) )
* 规则:修饰符(可以不写,但不能用*) +返回类型+哪些包下的类+哪些方法+方法参数“*” 代表不限,“.." 两个点代表参数不限。
  1. 3.定义通知
  • 利用通知的5种类型注解@Before. @After、 @AfterReturning、@AfterThrowing、 @ Around来完成在某些切点的増强动作。如@Before(" myPointcut()"), myPointcut为第二步骤定义的切点
  • 代码实现
package com.yang.aop.controller;
import com.yang.aop.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
/**
 * @Description:
 * @Author: Yang.Guo
 * @Date: 2021/08/26/10:44
 */
@RestController
public class HelloController {
    @Autowired
    private HelloService helloService;
    @RequestMapping("/hello")
    public String hello(@RequestParam("name") String name) {
        return helloService.testServiceAop(name);
    }
    @RequestMapping("/A")
    public String A(@RequestParam("name") String name) {
        return helloService.A(name);
    }
    @RequestMapping("/testThrow")
    public String testThrow(@RequestParam("name") String name) {
        return helloService.testThrow(name);
    }
}
package com.yang.aop.service;
import org.springframework.stereotype.Service;
@Service
public interface HelloService {
    String testServiceAop(String name);
    /**
     * 测试拦截Service层返回数据
     * @param name
     * @return
     */
    String A(String name);
    /**
     * 测试抛异常
     * @param name
     * @return
     */
    String testThrow(String name);
}
package com.yang.aop.service.impl;
import com.yang.aop.service.HelloService;
import org.springframework.stereotype.Service;
@Service("HelloServiceImpl")
public class HelloServiceImpl implements HelloService {
    @Override
    public String testServiceAop(String name) {
        return name;
    }
    @Override
    public String A(String name) {
        return "name";
    }
    @Override
    public String testThrow(String name) {
        throw new RuntimeException("测试抛异常");
    }
}
package com.yang.aop.aspact;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
/**
 * @Description:
 * @Author: Yang.Guo
 * @Date: 2021/08/26/10:47
 */
@Aspect  // 设置该类为切面类
@Slf4j
@Component  // 将切面类注入进Spring中
public class LoggerAspact {
    /**
     *  设置切点拦截
     * 使用注解@Pointcut 完成 如:@Pointcut(public * com.xxx.xxx.*.*(..))
     * 规则:修饰符(可以不写,,但不能用*)+ 返回值类型 + 哪些包下的类 + 哪些方法 + 方法参数
     * "*" 代表不限
     * ".." 代表参数不限
     * @Pointcut(value = "execution(* com.yang.aop.controller.*.*(..))")
     *
     */
    @Pointcut(value = "execution(* com.yang.aop.controller.*.*(..))") // 设置切点集合
    public void myPointcut(){
    }
    /**
     *  定义通知,也就是切点拦截后执行的动作
     * 利用通知的5种类型注解:
     * @Before
     * @After
     * @AfterReturning
     * @AfterThrowing
     * @Around
     * 来完成某个切点的增强动作
     * 如@before("myPointcut()"),myPointcut()为第二部定义的切点
     */
    /**
     *
     * @param pjp
     * @return
     */
    @SneakyThrows
    @Around("myPointcut()")
    public Object myLogger(ProceedingJoinPoint pjp){
        String className = pjp.getClass().getName().toString();
        String methodName = pjp.getSignature().getName();
        Object[] array = pjp.getArgs();
        ObjectMapper objectMapper = new ObjectMapper();
        log.info("调用前:类:"+className + "方法:"+methodName + "参数为:" + objectMapper.writeValueAsString(array));
        Object proceed = pjp.proceed();
        log.info("调用后:类:"+className + "方法:"+methodName + "参数为:" + objectMapper.writeValueAsString(proceed));
        return proceed;
    }
}
package com.yang.aop.aspact;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@Aspect
public class ServiceAspact {
    @Pointcut(value = "execution( * com.yang.aop.service.impl.*ServiceImpl.A(..))")
    public void serviceAspact(){
    }
    @Around("serviceAspact()")
    public Object doBefore(ProceedingJoinPoint joinPoint) throws Throwable {
        log.info("拦截Service层的切面");
        Object proceed = null;
        try {
            // 执行拦截的目标 (执行ServiceImpl里边的方法)
            proceed = joinPoint.proceed();
            // proceed 为执行拦截目标方法后的返回值!
            // 抛异常,不抓会直接抛异常,抓异常处理后,proceed 返回值为 null
        }catch (Exception e){
            e.printStackTrace();
        }
        log.info("拦截Service层的切面,执行完成");
        // joinPoint.getArgs(); 可以获取拦截目标的参数
        Object[] args = joinPoint.getArgs();
        System.out.println(args);
        // 通过 joinPoint.proceed(); 可以执行拦截的目标!
        // TODO: 2022/2/21 切记, joinPoint.proceed();执行后的值 就是拦截目标的返回值
        // TODO: 2022/2/21 切记,拦截以后一定要将执行后的返回值,return出去!!! 
        return proceed;
    }
}


相关文章
|
7月前
|
Java Spring
|
2月前
|
Java 测试技术 Spring
Spring-AOP
Spring-AOP
|
7月前
|
XML 人工智能 运维
面向AOP(2)spring
面向AOP(2)spring
59 2
面向AOP(2)spring
|
安全 Java Spring
1.7 Spring AOP
AOP的概念AOP(Aspect-Oriented Programming),即面向切面编程。AOP采取横向抽取机制,即将分散在各个方法中的重复代码提取出来,然后在程序编译或运行阶段,将这些抽取出来的代码应用到需要执行的地方。AOP把程序分为核心业务逻辑和非核心的公共服务,AOP的关注点是非核心的公共服务,主要处理日志记录、性能统计、安全控制、事务处理、异常处理等功能。AOP面向切面编程的优势。
146 0
|
7月前
|
Java Spring
【spring(三)】AOP总结
【spring(三)】AOP总结
|
7月前
|
Java 测试技术 数据安全/隐私保护
Spring:AOP
AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构
41 0
|
XML 缓存 监控
spring之aop
spring之aop
73 0
|
Java 程序员 编译器
对Spring AOP的理解
对Spring AOP的理解
52 0
|
XML 存储 Java
Spring AOP 如何生效
《基础系列》
170 0
|
Java Spring 容器
Spring的AOP详解
Spring的AOP详解
205 0
Spring的AOP详解