spring——AOP原理及源码(一)
系列介绍
共分为五篇,按照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原理及源码(一)的更多相关文章
- spring——AOP原理及源码(四)
前情回顾: 上文我们一路分析了从容器创建开始直到我们的AOP注解导入的核心组件AnnotationAwareAspectJAutoProxyCreator执行postProcessBeforeInst ...
- spring——AOP原理及源码(五)
前情回顾: 在上一篇中,通过 wrapIfNecessary 方法,我们获取到了合适的增强器(日志方法)与业务类进行包装,最终返回了我们业务类的代理对象. 本篇我们将从业务方法的执行开始,看看增强器( ...
- spring——AOP原理及源码(二)
回顾: 在上一篇中,我们提到@EnableAspectJAutoProxy注解给容器中加入了一个关键组件internalAutoProxyCreator的BeanDefinition,实际类型为 An ...
- spring——AOP原理及源码(三)
在上一篇中,我们创建并在BeanFactory中注册了AnnotationAwareAspectJAutoProxyCreator组件.本篇我们将要探究,这个组件是在哪里以及何时发挥作用的. 调试的起 ...
- 【Spring】Spring IOC原理及源码解析之scope=request、session
一.容器 1. 容器 抛出一个议点:BeanFactory是IOC容器,而ApplicationContex则是Spring容器. 什么是容器?Collection和Container这两个单词都有存 ...
- Spring AOP介绍及源码分析
转自:http://www.uml.org.cn/j2ee/201301102.asp 软件开发经历了从汇编语言到高级语言和从过程化编程到面向对象编程:前者是为了提高开发效率,而后者则使用了归纳法,把 ...
- Spring中AOP原理,源码学习笔记
一.AOP(面向切面编程):通过预编译和运行期动态代理的方式在不改变代码的情况下给程序动态的添加一些功能.利用AOP可以对应用程序的各个部分进行隔离,在Spring中AOP主要用来分离业务逻辑和系统级 ...
- spring MVC 原理及源码解析
首先要知道springmvc的核心控制器dispatcherServlet(继承自httpServlet) 一般httpServlet的请求过程: 1.初始化(创建servlet实例时)时会执行ser ...
- Spring MVC工作原理及源码解析(三) HandlerMapping和HandlerAdapter实现原理及源码解析
1.HandlerMapping实现原理及源码解析 在前面讲解Spring MVC工作流程的时候我们说过,前端控制器收到请求后会调⽤处理器映射器(HandlerMapping),处理器映射器根据请求U ...
随机推荐
- Monkey通过安装包获取包名
在monkey命令中,包名常作为一个参数.但我们经常知道apk文件,却不知道包名. 如何获取包名呢? 方法一:AAPT 在SDK的build-tools目录下,aapt工具可以查看,创建,更新zip格 ...
- 《VSTO开发中级教程》刘永富 著 清华大学出版社 在线购买
现在可以和作者 刘永富 通过“二手书直卖”这个APP直接买书. 二手书直卖 的下载方法: 方法一:加QQ群61840693,群共享中搜索“二手书直卖”,下载后打开即可. 方法二:从本帖下载:二手书直卖 ...
- 史上最强maven配置详情
史上最强maven配置详情 优点 对第三方依赖库进行了统一的版本管理 统一了构建过程 统一了项目的目录结构 构建 清理 : mvn clear 编译 : mvn compile 测试 : mvn te ...
- servletHomeWork
2. http全称是什么? 超文本传输协议(HTTP, HyperText Transfer Protocol)是互联网上应用为最广泛的一种网络协议. 3.http协议是无状态的协议是什么意思?请说明 ...
- Sam format
reference:https://davetang.org/wiki/tiki-index.php?page=SAM @SQ SN:contig1 LN:9401 (序列ID及长度) 参考序列名,这 ...
- Java多线程处理任务(摘抄)
很多时候,我们需要对一个庞大的队列或者二维数组进行处理.这些处理可能是循环的,比如给一个excel多个sheet的联系人列表发邮件.很幼稚的方法就是用一个或者两个FOR循环搞定,对于庞大的数据有得让你 ...
- Uber退出东南亚留下烂摊子,给“中国式并购”带来哪些启示
当下,从全球范围内来看很多互联网企业都采用了"复制+粘贴"的疯狂推进模式.它们往往在某一个国家或地区取得领先优势后,就快速将相同模式在全球推进去占领当地市场.无论结果是一家独大占据 ...
- 03-Java的基础语法
一个Java程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作.下面简要介绍下类.对象.方法和实例变量的概念. 对象:对象是类的一个实例,有状态和行为.例如,一条狗是一个对象,它的 ...
- SQL热备原理
- 利用数目找中位数(牛客第七场E)
https://ac.nowcoder.com/acm/contest/887/E 树状数组做法(代码有注释) #include<bits/stdc++.h> using namespac ...