Spring源码分析-深入浅出AOP(图文分析)

这篇文章主要解决三个问题

  1. 什么是AOP
  2. Spring 中怎么实现的AOP
  3. AOP的应用场景



首先我们看下 到底什么是AOP

AOP的基本概念


AOP 官方定义

    Aspect-Oriented Programming (AOP) complements Object-Oriented Programming (OOP) by providing another way of thinking about program structure.
( 面向方面的编程(AOP)是面向对象编程(OOP)的补充,它提供了另一种关于程序结构的思考方式)

这个解释听起来很抽象,如何理解呢?

我们知道面向对象编程关注的是对象和对象的行为,相同类似行为或属性的对象可以通过继承来实现,但是如果我们关注的是毫不相干的一组对象的特定方法 怎么办

一组对象和对象的行为

如图,我们要关注的方法 散布在不同类中,如果想要在这些方法中加入相同的处理逻辑,过去我们采用的方法只能是硬编码,但是这样会造成大量的重复代码,不便于维护,AOP的出现就是解决针对这种问题的一种实现模式。

首先我们看下AOP中涉及到的几个重要的基本概念

Aspect:字面意思是切面,官方解释 a modularization of a concern that cuts across multiple classes ( 横切多个类的一个关注点模块),简单说就是对类具体行为的关注点集合,这样解释还是太抽象

Aspect

上图中 可以看到 对多个类关注的方法 形成的一个切面,就是Aspect

Join point: a point during the execution of a program, such as the execution of a method or the handling of an exception. In Spring AOP, a join point always represents a method execution(程序执行过程中的里连接点,比如 方法调用或者异常处理。在spring aop中,一个连接点通常代表一个方法的调用,我们可以认为一个方法的执行就是一个连接点

Join Point

Advice: action taken by an aspect at a particular join point. Different types of advice include “around,” “before” and “after” advice. (Advice types are discussed below.)(通知:切面在特定连接点上产生的动作,包括多种不同类型的通知,比如 环绕通知 aroud,前置通知before和后置通知after等)

简单的说就是我们要在切面上做什么事情(动作-action)

Advice

Pointcut: a predicate that matches join points. Advice is associated with a pointcut expression and runs at any join point matched by the pointcut (for example, the execution of a method with a certain name).(切入点,匹配连接点的断言,通知与切入点表达式相关联,并且在任何匹配该断言的连接点上执行(比如一个特定名称的方法执行))

用来描述我们要在哪些地方执行,也可以说成是 用表达式匹配(正则断言)的切入点

Point cut

Target object: object being advised by one or more aspects. Also referred to as the advised object(目标对象 ,被一个或多个切面通知的对象,通常被称为被通知对象)

Target Object

Proxy Pattern(代理模式)
GOF 定义
What problems can the Proxy design pattern solve? (代理模式能解决什么问题)

  • The access to an object should be controlled.(控制被访问对象)
  • Additional functionality should be provided when accessing an
    object.(给被访问对象提供额外功能)

What solution does the Proxy design pattern describe?(代理模式的解决方案是如何描述的)
Define a separate Proxy object that can be used as substitute for another object (Subject) and implements additional functionality to control the access to this subject.
(定义一个单独的代理类,用来提供对目标对象的代理访问 如下图所示 代理类会默认实现目标对象的接口,并在此基础上提供其他功能)

Proxy Pattern

Spring AOP Revolution(进化史)

spring AOP revolution

详细内容可以参考 这里不再详述
http://cxis.me/2017/04/10/Spring%E4%B8%ADAOP%E7%9A%84%E9%85%8D%E7%BD%AE%E4%BB%8E1.0%E5%88%B05.0%E7%9A%84%E6%BC%94%E8%BF%9B/

Spring如何实现AOP


我们重点使用最新最简洁的spring 5 自动配置模式来进行讲解
这里我们通过一个性能拦截器来演示spring aop的代码流程,这个拦截器可以打印服务层所有方法的执行时间

CODE

业务接口定义

/**
 * 业务服务接口
 */
public interface IBusinessService {
   

    //业务执行方法A
    void executeBusinessA();

    //业务执行方法B
    void executeBusinessB();


}

业务实现类

/**
 * 业务实现类
 */
@Service("businessService")
public class BusinessServiceImpl implements IBusinessService {
   

    private  static final Logger logger = LogManager.getLogger(BusinessServiceImpl.class);

    /**
     * 常规业务方法(不超时)
     */
    public void executeBusinessA() {
        //模拟一个执行时间
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            System.out.println(e.getMessage());
        }

        logger.info("executing business in methodA");

    }


    /**
     * 超时业务方法
     */
    public void executeBusinessB() {
        //模拟一个超时执行时间
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            System.out.println(e.getMessage());
        }

        logger.info("executing business in methodB");

    }
}

性能分析器

@Component
@Aspect
public class PerformanceAnalysisInterceptor {
   

    private static Logger logger = LogManager.getLogger(PerformanceAnalysisInterceptor.class);
    private static final long DELAY_MINUTE = 1000;

    public static final String POINTCUT = "execution (* aop.service.impl.BusinessServiceImpl.*(..))";



    @Around(POINTCUT)
    public Object analysisAround(ProceedingJoinPoint joinPoint) {
        Object obj = null;
        long startTime = System.currentTimeMillis();
        try {
            obj = joinPoint.proceed(joinPoint.getArgs());
        } catch (Throwable e) {
            logger.error(e.getMessage());
        }

        long endTime = System.currentTimeMillis();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        String methodName = signature.getDeclaringTypeName() + "." + signature.getName();
        long diffTime = endTime - startTime;

        logger.info("-----" + methodName + "执行时间 :" + diffTime + " ms");
        if(diffTime > DELAY_MINUTE)
        delayWarning(methodName, diffTime-DELAY_MINUTE);

        return obj;
    }

    private void delayWarning(String methodName,long delayTime) {
            logger.warn("-----" + methodName + "超时 :" + delayTime + " ms");
    }



}

xml自动化配置

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

    <context:component-scan base-package="aop"/>
    <aop:aspectj-autoproxy/>

</beans>

主函数调用执行

public class AopMain {

    public static void main(String[] args) {

        ClassPathXmlApplicationContext f = new ClassPathXmlApplicationContext("spring-aop.xml");
        IBusinessService businessService = (IBusinessService) f.getBean("businessService");
        businessService.executeBusinessA();
        businessService.executeBusinessB();

    }
}

concole打印结果

11:21:36.344 [main] INFO  org.springframework.context.support.ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@7dc222ae: startup date [Sat Dec 09 
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值