系列介绍

共分为五篇,按照AOP的运行流程演示并分析springAOP源码,总结流程

系列流程

从AOP实例的构建到重要组件分析、基本运行流程、关键方法调用、原理总结等几个方面一步步分解AOP源码

本篇概述

为读者演示构建AOP实例及AOP核心组件分析


一、项目构建

读者可直接下载示例工程,或复制以下的代码到本地工程开启教程。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <groupId>com.tlj</groupId>
<artifactId>spring-test</artifactId>
<version>1.0-SNAPSHOT</version> <dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.13.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency> <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.12.RELEASE</version>
</dependency>
</dependencies> </project>

pom.xml

package config;

import aop.LogAspects;
import aop.MathCalculator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy; @EnableAspectJAutoProxy
@Configuration
public class ConfigOfAOP { @Bean
public MathCalculator calculator(){
return new MathCalculator();
} @Bean
public LogAspects logAspects(){
return new LogAspects();
}
}

ConfigOfAOP

package aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*; import java.util.Arrays; /**
* 切面类
*/
@Aspect
public class LogAspects { @Pointcut("execution(public int aop.MathCalculator.*(..))")
public void poinCut(){} @Before("poinCut()")
public void logStart(JoinPoint joinPoint){
Object[] args = joinPoint.getArgs();
System.out.println(joinPoint.getSignature().getName()+" 运行。。。@Before "+ Arrays.asList(args));
} @After("poinCut()")
public void logEnd(){
System.out.println("除法结束..@After");
} @AfterReturning(value = "poinCut()",returning = "result")//获取方法返回值
public void logReturning(Object result){
System.out.println("除法正常返回..@AfterReturning "+result);
} @AfterThrowing(value = "poinCut()",throwing = "e")
public void logException(Exception e){
System.out.println("除法异常..@AfterThrowing "+e);
}
}

LogAspects

package aop;

public class MathCalculator {

    public int div(int i,int j){
System.out.println("MathCalculator");
return i/j;
}
}

MathCalculator

项目目录结构如下:

到这里,构建了一个简单的切面功能demo


二、运行测试

打开测试类,运行测试方法


最终效果

总共打印了四行,第二行是业务方法的调用,其他都是调用日志切面类中的方法打印的。

这就是AOP的使用效果,除了用在日志,还有其他很多用法,这里就不赘述了。

三、关键组件探究

为什么AOP能在业务方法调用的前后和发生异常时调用切面方法呢,首先我们需要了解它引入了什么组件。

为了让AOP起作用,我们需要在配置类上添加@EnableAspectJAutoProxy注解,从字面上看,翻译为启动切面自动代理,那它是怎么启动的呢

ctrl+鼠标左键进入这个注解,我们可以看到EnableAspectJAutoProxy接口使用@Import注解导入了AspectJAutoProxyRegistrar这个类


再次ctrl+鼠标左键进入AspectJAutoProxyRegistrar,可以看到,它实现了ImportBeanDefinitionRegistrar接口。

此接口中的registerBeanDefinitions方法,正是用来向容器中注册组件的。

接下来来看@EnableAspectJAutoProxy注解到底给容器中注册了什么组件。这是AOP实现的关键。

四、调试寻找组件

如下图,我们在ImportBeanDefinitionRegistrar接口的注册方法中打上断点。


点击debug开始调试,程序来到了AspectJAutoProxyRegistrar的registerBeanDefinitions方法

正在执行的是AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)

(字面意思为:注册切面自动代理创造组件如果需要的话)


接着进入这个方法直到以下这个方法,可以看到返回的是BeanDefinition类型,而BeanDefinition是用来保存bean定义信息的

上图所示,一进来先进行判断,如果容器中存在AUTO_PROXY_CREATOR_BEAN_NAME定义信息,进行一些操作,最后return null。

如果不存在,可以看到在125行已经有注册名为AUTO_PROXY_CREATOR_BEAN_NAME的组件的动作,要将定义信息注册到容器中。

把鼠标放在AUTO_PROXY_CREATOR_BEAN_NAME上,可以看到它名为internalAutoProxyCreator

接着我们进行下一步,到110行时,显然第一次容器中不存在这个类,所以跳过if{}中的内容

到121行时,通过bean的各种定义信息,new一个定义bean,用来保存这个bean的各种定义信息

通过cls的信息,发现注册的internalAutoProxyCreator实际为AnnotationAwareAspectJAutoProxyCreator

到125行时,已经设置好AnnotationAwareAspectJAutoProxyCreator的各种属性

并将其命名为internalAutoProxyCreator注册进容器,在126行进行返回。

注意:这里注册的是BeanDefinition,也就是bean的定义信息,并没有创建bean实例

总结

到此为止@EnableAspectJAutoProxy给容器中添加了internalAutoProxyCreator的BeanDefinition组件

internalAutoProxyCreator中实际又是AnnotationAwareAspectJAutoProxyCreator这个类

所以我们可以得出AnnotationAwareAspectJAutoProxyCreator就是实现AOP的核心组件

接下来我们来看AnnotationAwareAspectJAutoProxyCreator的继承关系,看它到底是什么

五、AnnotationAwareAspectJAutoProxyCreator组件是什么

进入这个类,发现它继承了AspectJAwareAdvisorAutoProxyCreator

那么AspectJAwareAdvisorAutoProxyCreator又是什么呢,接着进入AspectJAwareAdvisorAutoProxyCreator

发现AspectJAwareAdvisorAutoProxyCreator又继承了AbstractAdvisorAutoProxyCreator

我们接着进入AbstractAdvisorAutoProxyCreator中查看

可以看到AbstractAdvisorAutoProxyCreator继承了AbstractAutoProxyCreator

再进入AbstractAutoProxyCreator

可以看到AbstractAutoProxyCreator继承了ProxyProcessorSupport

并实现了SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware两个接口

由于接下来继承的ProxyProcessorSupport是一个基础工具类,就不往下分析了


接下来我们主要看这两个接口

SmartInstantiationAwareBeanPostProcessor:从名字中带有PostProcessor看出是一个后置处理器接口

BeanFactoryAware:底层组件接口,和其他XXXAware一样,实现XXXAware接口就可以调用XXX组件

经过层层的进入,可以得到如下的关系:

从图得出结论——AnnotationAwareAspectJAutoProxyCreator是一个后置处理器后置处理器原理

总结

  经过以上五个步骤,我们了解了AOP的使用效果

  找到了AOP的核心组件AnnotationAwareAspectJAutoProxyCreator

  理清了AnnotationAwareAspectJAutoProxyCreator的继承实现关系

  发现了AOP的核心组件本质上是一个后置处理器

下篇预知:在下一篇中我们将从核心组件在哪发挥作用,何时发挥,以及做了什么,一步步深入原理。

spring——AOP原理及源码(一)的更多相关文章

  1. spring——AOP原理及源码(四)

    前情回顾: 上文我们一路分析了从容器创建开始直到我们的AOP注解导入的核心组件AnnotationAwareAspectJAutoProxyCreator执行postProcessBeforeInst ...

  2. spring——AOP原理及源码(五)

    前情回顾: 在上一篇中,通过 wrapIfNecessary 方法,我们获取到了合适的增强器(日志方法)与业务类进行包装,最终返回了我们业务类的代理对象. 本篇我们将从业务方法的执行开始,看看增强器( ...

  3. spring——AOP原理及源码(二)

    回顾: 在上一篇中,我们提到@EnableAspectJAutoProxy注解给容器中加入了一个关键组件internalAutoProxyCreator的BeanDefinition,实际类型为 An ...

  4. spring——AOP原理及源码(三)

    在上一篇中,我们创建并在BeanFactory中注册了AnnotationAwareAspectJAutoProxyCreator组件.本篇我们将要探究,这个组件是在哪里以及何时发挥作用的. 调试的起 ...

  5. 【Spring】Spring IOC原理及源码解析之scope=request、session

    一.容器 1. 容器 抛出一个议点:BeanFactory是IOC容器,而ApplicationContex则是Spring容器. 什么是容器?Collection和Container这两个单词都有存 ...

  6. Spring AOP介绍及源码分析

    转自:http://www.uml.org.cn/j2ee/201301102.asp 软件开发经历了从汇编语言到高级语言和从过程化编程到面向对象编程:前者是为了提高开发效率,而后者则使用了归纳法,把 ...

  7. Spring中AOP原理,源码学习笔记

    一.AOP(面向切面编程):通过预编译和运行期动态代理的方式在不改变代码的情况下给程序动态的添加一些功能.利用AOP可以对应用程序的各个部分进行隔离,在Spring中AOP主要用来分离业务逻辑和系统级 ...

  8. spring MVC 原理及源码解析

    首先要知道springmvc的核心控制器dispatcherServlet(继承自httpServlet) 一般httpServlet的请求过程: 1.初始化(创建servlet实例时)时会执行ser ...

  9. Spring MVC工作原理及源码解析(三) HandlerMapping和HandlerAdapter实现原理及源码解析

    1.HandlerMapping实现原理及源码解析 在前面讲解Spring MVC工作流程的时候我们说过,前端控制器收到请求后会调⽤处理器映射器(HandlerMapping),处理器映射器根据请求U ...

随机推荐

  1. rare alleles

    I.4 Where the rare alleles are found p是基因A的频率,N是个体数目(也就是基因型个数,所以基因个数是2n,所以全部个体的基因A的个数是2np),p方是PAA,np ...

  2. iMX6Q/PLUS开发板烧写设备树内核的Ubuntu系统

    基于迅为-iMX6D.iMX6Q 和 iMX6PLUS 三个硬件版本,设备树镜像的烧写方法以及镜像所在目录,镜像名称全部一致,所以作者将烧写章节合并到一起. 请注意,如果购买的是 iMX6D 版本,想 ...

  3. 八、linux-mysql的mysql主从复制原理和实战

    1.mysql主从复制介绍 mysql支持单向.双向.链式级联.实时.异步复制,在复制过程中,一台服务器充当主服务器(Master),而一个或多个其它服务器充当从服务器(Slave). 复制:单向同步 ...

  4. 六、linux-mysql的mysql字符集问题

    一.什么是字符集? 字符集是用来定义mysql数据字符串的存储方式,而校对规则则是定义比较字符串的方式.mysql字符集包含字符集和校对规则. 二.字符集的选择 常见的字符集中,中英混合环境建议用UT ...

  5. Octave 常用命令

    GNU Octave 官方文档 GNU Octave Documentation(Online) GNU Octave Documentation(PDF) 安装额外的包 Installing and ...

  6. D. Colored Boots(STL)

    There are nn left boots and nn right boots. Each boot has a color which is denoted as a lowercase La ...

  7. scala编程(七)——内建控制结构

    几乎所有的 Scala 的控制结构都会产生某个值.这是函数式语言所采用的方式,程序被看成是计算值的活动,因此程序的控件也应当这么做.另外,指令式语言经常具有三元操作符(如 C,C++和 Java 的? ...

  8. The sequence and de novo assembly of the giant panda genome.ppt

    sequencing:使用二代测序原因:高通量,短序列 不用长序列原因: 1.算法错误率高 2.长序列测序将嵌合体基因错误积累.嵌合体基因:通过重组由来源与功能不同的基因序列剪接而形成的杂合基因 se ...

  9. [LC] 398. Random Pick Index

    Given an array of integers with possible duplicates, randomly output the index of a given target num ...

  10. 信贷建模little tricks

    一.逻辑回归 概率分类模型 选取样本:对逻辑回归这种概率分类模型来说维持原来样本真实的分布还是有必要的,但是对一些树模型来说可以通过采样来平衡样本. 原来评分卡建模还有个拒绝推断,就是为了还原人群真实 ...