Spring核心功能——AOP(面向切面编程)

目录

AOP

1 介绍

2 AOP术语

3 应用场景

4 演示


 

AOP

1 介绍

Spring中另外一个核心功能,AOP


AOP(Aspect Oriented Programming),即面向切面编程.

OOP(Object Oriented Programming ),即面向对象编程.

AOP面向切面编程,利用 一种称为"横切"的技术,剖开封装的对象内部,并将那些影响了 多个类的公共行为抽取出封装到一个可重用模块),并将其命名 为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。

 

面向切面编程的作用:就是将项目中与核心逻辑无关的代码横向抽取成切面类,通过织入作用到目标方法,以使目标方法执行前后达到增强的效果.

原理: AOP底层使用的就是动态代理,给AOP指定哪些类型(目标类)需要增强,就会产生对应的代理对象,代理对象执行方法前后会先执行增 强的方法.

好处:减少系统的重复代码,降低模块之间的耦合度,便于维护,可以只关注核心业务

补充:
AOP底层实现原理是代理设计模式,且是动态代理

动态代理(jdk动态代理技术 / cglib动态代理技术)

jdk代理技术,要求目标类必须是接口
cglib代理技术, 目标类可以是接口也可以是类

2 AOP术语

连接点(Joinpoint):连接点是程序类中客观存在的方法,可被Spring拦截并切入内容。即每个方法在切入之前,都是连接点

切入点(Pointcut):被Spring切入连接点。即真正会增强的目标方法

通知、增强(Advice):可以为切入点添加额外功能,分为:前置通知、后置通知、异常通知、环绕通知等。

目标对象(Target):被代理的目标对象

织入(Weaving):把通知应用到具体的类,进而创建新的代理类的过程。

代理(Proxy):被AOP织入通知后,产生的结代理类。

切面(Aspect):由切点和通知组成

3 应用场景

  • 事务管理

    • 后续spring管理事务用的AOP原理

  • 权限校验

    • 后期使用Spring Security注解开发时,其实利用了AOP思想

  • 日志记录

  • 性能检测

  • 等等

4 演示

需求: 实现业务层代码执行时,能出现一些增强的效果

一般写在service层是咱们要被增强的地方

开发步骤

  1. 创建切面类,类上加注解

    • @Component ,加上该注解,springboot框架就会创建该类对象

    • @Aspect , 加上该注解,springboot框架内部就会知道该类是一个切面类

    • 设置切入点方法,并加注解

      • @Pointcut , 用于定义要增强的目标方法路径

  1. 设置各种增强(或者叫通知)方法

  • 注解 解释
    @Around 环绕通知
    @Before 前置通知
    @After 后置通知
    @AfterReturning 后置返回通知
    @AfterThrowing 异常通知

1.pom.xml添加aop依赖

        
            org.springframework.boot
            spring-boot-starter-aop
        
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import com.qf.annotation.MyLog;
import com.qf.model.Log;
import com.qf.model.User;
import com.qf.service.MyLogService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.util.WebUtils;

/**
 * @Author yhf
 * @Date 2024/9/3
 * @Desc 200不是二百
 */
@Component
@Aspect
public class MyLogAspect {
    // 注入业务层对象
    @Autowired
    private MyLogService logService;

    // 切入的目标是注解
    @Before("@annotation(com.qf.annotation.MyLog)")
    public void after(JoinPoint joinPoint) {
        // 调用下方自定义方法,获得注解中的值
        String desc = getAnnoDesc(joinPoint);

        System.out.println("注解中的值:" + desc);
        // 以下代码需要使用Springmvc,既控制层也需要由Spring托管,才会获得ip
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes( )).getRequest( );
        // 能取出数据的前提是登录时将用户信息存储到session
        User user = (User) WebUtils.getSessionAttribute(request, "user");

        String name = "未登录";
        if (user != null) { // 防止出现空指针异常
            name = user.getName( );
        }

        //ip
        String ip = request.getRemoteAddr( );
        System.out.println("请求对象的ip:" + ip);
        // 封装数据
        Log log = new Log( );
        log.setName(name);
        log.setIp(ip);
        log.setLogTime(new Date());
        log.setLog(desc);
        // 调用业务层,执行插入
        logService.insertLog(log);
    }

    /*
     * 封装的方法,通过反射技术获得目标方法上的注解的值
     */
    public static String getAnnoDesc(JoinPoint joinPoint) {
        String value = "";
        try {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature( );
            // 获得目标方法对象
            Method method = signature.getMethod( );
            // 获得目标方法对象上的日志注解
            MyLog myLog = method.getDeclaredAnnotation(MyLog.class);
            // 获得日志注解上的值
            value = myLog.value( );
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return value;
    }

 

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