动态代理以及对应Spring中AOP源码分析
AOP(面向切面编程)在Spring中是被广泛应用的(例如日志,事务,权限等),而它的基本原理便是动态代理。
我们知道动态代理有两种:基于JDK的动态代理以及基于CGlib动态代理。以下是两种动态代理的实现方式:
//JDK动态代理
public class JDKProxy implements InvocationHandler { private Object object;// 被代理人 //这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了动态代理。但是要注意下面的newProxyInstance()中的参数
public Object getInstance(Object object) {
this.object = object;
//与cglib的区别在于这里构建代理对象的时候需要传入被代理对象的接口对象,第二个参数。而cglib不需要被代理对象实现任何接口即可
return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), this);
} //代理对象真正调用的方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("doSomething---------start");
method.invoke(object, args);
System.out.println("doSomething---------end");
return null;
} } //CGlib动态代理
public class CglibProxy implements MethodInterceptor {
private Object targetObject; // 这里的目标类型为Object,则可以接受任意一种参数作为被代理类,实现了动态代理
public Object getInstance(Object target) {
this.targetObject = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(this);
//注意该处代理的创建过程
Object proxyObj = enhancer.create();
return proxyObj;// 返回代理对象
} //代理对象真正调用的方法
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object obj = null;
System.out.println("doSomething---------start");
obj = method.invoke(targetObject, args);
System.out.println("doSomething---------end");
return obj;
} }
具体两种动态代理的差异在网上有很多各个方面的比较,在这里我就不再赘述。下面我再说说在Spring 5.0.3.RELEASE中实现AOP的原理(我的github中也有详细的源码注释)。
在注解版的Spring AOP当中我们会有如下的代码配置,其中@EnableAspectJAutoProxy便是开启AOP支持的关键。
@EnableAspectJAutoProxy //开启基于注解的AOP模式
@Configuration
@ComponentScan(value = {"com.aop"})
public class AnnotationAopConfig { @Bean("student")
public Student getStudent() { //把我们普通的Java Bean定义出来交给IOC容器管理
return new Student();
} @Bean
public LogAspect getLogAspect() { //定义切面类
return new LogAspect();
}
}
我们跟踪一下@EnableAspectJAutoProxy的源码来看看它的定义,会发现它利用@Import导入了AspectJAutoProxyRegistrar.class组件:代码块一
由AspectJAutoProxyRegistrar.Class的定义可知其实现了ImportBeanDefinitionRegistrar接口,所以在IOC容器初始化的时候会调用该类的registerBeanDefinitions方法。通过观察该方法实现,我们可以看到一行关键的代码AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);:代码块二
这行代码中所需要注册的到底是什么东西呢?我们进一步一探究竟。在持续跟入代码的过程中我们可以找到这么一块代码:return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);:代码块三
观察源码可以得知,该方法会将AnnotationAwareAspectJAutoProxyCreator类封装为一个RootBeanDefinition然后添加到BeanDefinition的注册类当中以AUTO_PROXY_CREATOR_BEAN_NAME。我们也可以找到关于AUTO_PROXY_CREATOR_BEAN_NAME的定义:代码块四
我们再分析一下AnnotationAwareAspectJAutoProxyCreator.Class的源码,看看此类到底有何特别之处。观察源码我们可以发现AnnotationAwareAspectJAutoProxyCreator是BeanPostPrcsessor的子类:代码块五
/**********************代码块一***********************/ @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class) //导入AspectJAutoProxyRegistrar组件
public @interface EnableAspectJAutoProxy {
/**********************代码块二***********************/
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar { @Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry); //如果需要的话注册AspectJAnnotationAutoProxy
/**********************代码块三***********************/
@Nullable
public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry,
@Nullable Object source) { return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}
/**********************代码块四***********************/
/**
* The bean name of the internally managed auto-proxy creator.
*/
public static final String AUTO_PROXY_CREATOR_BEAN_NAME = "org.springframework.aop.config.internalAutoProxyCreator";
private static BeanDefinition registerOrEscalateApcAsRequired(Class<?> cls, BeanDefinitionRegistry registry,
@Nullable Object source) { Assert.notNull(registry, "BeanDefinitionRegistry must not be null"); if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
int requiredPriority = findPriorityForClass(cls);
if (currentPriority < requiredPriority) {
apcDefinition.setBeanClassName(cls.getName());
}
}
return null;
} RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
beanDefinition.setSource(source);
beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);//注册
return beanDefinition;
}
/**********************代码块五***********************/
AnnotationAwareAspectJAutoProxyCreator
AnnotationAwareAspectJAutoProxyCreator
extends AspectJAwareAdvisorAutoProxyCreator
extends AbstractAdvisorAutoProxyCreator
extends AbstractAutoProxyCreator
extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
extends ...InstantiationAwareBeanPostProcessor Ordered
extends BeanPostProcessor
从以上代码,我们可以知道@EnableAspectJAutoProxy大概做了这么一件事:将AnnotationAwareAspectJAutoProxyCreator.Class以名为“org.springframework.aop.config.internalAutoProxyCreator”的方式完成注册BeanDefinition的操作。
然后我们再看看这块内容对Spring容器启动过程的影响。
我们以下面的代码为入口进行分析:代码块一
我们进入IOC容器初始化过程看看对于进行了切面操作的类来说经历了哪些操作,通过断点我们可以跟踪到此代码处:PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);这里是实例化各种BeanPostProcessor,并将其实例存放在BeanFactory当中:代码块二(当中代码我挑出重要的部分。更加详细的Spring源码说明,请关注我的github)。
注册了BeanPostProcessor的实例,我们看看普通Bean对象的创建。跟踪源码可知:通过finishBeanFactoryInitialization等一系列方法的调用到getBean(beanName);方法之中,在getBean(beanName);后续的调用之中又经过了查询缓存,实例化依赖等一系列操作来到了createBean这个方法当中,我们可以通过代码详细分析其处理。我们可以找到Object beanInstance = doCreateBean(beanName, mbdToUse, args); 获取Bean实例的地方。 再跟进去看它的实现:代码块三
我们现在观察doCreateBean(beanName, mbdToUse, args); 源码,其中实现了移除缓存、创建实例、初始化实例等一系列操作,其中在exposedObject = initializeBean(beanName, exposedObject, mbd);中变有我们需要的关键信息。:代码块四
initializeBean(beanName, exposedObject, mbd);这个方法里面有applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);和applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);两个方法的调用。这里面的原理是获取所有的beanPostProcessors遍历调用其postProcessBeforeInitialization和postProcessAfterInitialization方法。这里我就不过多的赘述了。调试代码我们可以发现后续的调用链如下AbstractAutoProxyCreator#postProcessAfterInitialization-->AbstractAutoProxyCreator#wrapIfNecessary。在这里我们就可以判断其是否拥有增强器来创建代理对象,我们可以通过下面代码来观察其逻辑(增强器便是代理对象的各个方法封装起来的对象):代码块五
进入代理构建入口Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));以下便是通过默认的GClib来进行对象的一个封装。其代理封装的对象如下:代码块六
/**********************代码块一***********************/
@Test
public void test3() {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AnnotationAopConfig.class); //初始化IOC容器
String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames(); Student student = (Student) applicationContext.getBean("student");//从容器中获取对象
student.innerMethod(); //进行方法调用
applicationContext.close();
}
/**********************代码块二***********************/
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
/**
* IOC:stepA6-1 获取到所有已经定义了的,需要创建实例的所有实现BeanPostProcessor的类
* org.springframework.context.annotation.internalAutowiredAnnotationProcessor
* org.springframework.context.annotation.internalRequiredAnnotationProcessor
* org.springframework.aop.config.internalAutoProxyCreator
*/
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
....
/**
* 分离实现了PriorityOrdered、Ordered和rest接口的BeanPostProcessors
* 按顺序注册BeanPostProcessors
*/
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { //如果是PriorityOrdered的子类
....
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) { //AOP 匹配internalAutoProxyCreator,添加到orderedPostProcessorNames集合当中
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 首先, 注册实现PriorityOrdered接口的BeanPostProcessors
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement Ordered.
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class); //实例化internalAutoProxyCreator
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);//将internalAutoProxyCreator实例放进去
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors); //将BeanPostProcessor注册到BeanFactory
....
}
/**********************代码块三***********************/ protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
.... try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
//IOC:stepA10 给BeanPostProcessor一个机会返回一个代理实例代替Bean实例
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
} try {
Object beanInstance = doCreateBean(beanName, mbdToUse, args); //创建Bean实例
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
....
}
}
/**********************代码块四***********************/
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) { //如果是单例,从factoryBean实例缓存中移除
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);//创建实例
}
....
//缓存bean解决循环引用
....
// Initialize the bean instance.
//初始化bean实例
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper); //为Bean的属性赋值
exposedObject = initializeBean(beanName, exposedObject, mbd); //初始化对象
}
....
}
/**********************代码块五***********************/
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
} // Create proxy if we have advice.
//如果有增强器的话就创建代理
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));//创建AOP代理对象
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
} this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
/**********************代码块六***********************/
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable { private final AdvisedSupport advised; public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
} @Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);//根据将要执行的目标方法获取拦截器链
Object retVal;
// Check whether we only have one InvokerInterceptor: that is,
// no real advice, but just reflective invocation of the target.
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
// We can skip creating a MethodInvocation: just invoke the target directly.
// Note that the final invoker must be an InvokerInterceptor, so we know
// it does nothing but a reflective operation on the target, and no hot
// swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
// We need to create a method invocation...
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();//执行拦截器链
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
}
下面我们可以通过调试代码的方式来探究拦截器的调用。在这里拦截器是通过链式调用的方法按照顺序依次执行,我们可以通过时序图来很好的发现其调用逻辑。
好了,不知道通过源码阅读大家有没有对Spring AOP有了一个全新的认识呢?有任何疑问欢迎留言喔~
动态代理以及对应Spring中AOP源码分析的更多相关文章
- JDK动态代理[2]----JDK动态代理的底层实现之Proxy源码分析
在上一篇里为大家简单介绍了什么是代理模式?为什么要使用代理模式?并用例子演示了一下静态代理和动态代理的实现,分析了静态代理和动态代理各自的优缺点.在这一篇中笔者打算深入源码为大家剖析JDK动态代理实现 ...
- Spring AOP源码分析(三):基于JDK动态代理和CGLIB创建代理对象的实现原理
AOP代理对象的创建 AOP相关的代理对象的创建主要在applyBeanPostProcessorsBeforeInstantiation方法实现: protected Object applyBea ...
- Spring AOP 源码分析 - 创建代理对象
1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...
- spring aop 源码分析(三) @Scope注解创建代理对象
一.源码环境的搭建: @Component @Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON,proxyMode = ScopedP ...
- spring aop 源码分析(二) 代理方法的执行过程分析
在上一篇aop源码分析时,我们已经分析了一个bean被代理的详细过程,参考:https://www.cnblogs.com/yangxiaohui227/p/13266014.html 本次主要是分析 ...
- Spring基础系列-AOP源码分析
原创作品,可以转载,但是请标注出处地址:https://www.cnblogs.com/V1haoge/p/9560803.html 一.概述 Spring的两大特性:IOC和AOP. AOP是面向切 ...
- spring AOP源码分析(三)
在上一篇文章 spring AOP源码分析(二)中,我们已经知道如何生成一个代理对象了,那么当代理对象调用代理方法时,增强行为也就是拦截器是如何发挥作用的呢?接下来我们将介绍JDK动态代理和cglib ...
- Spring AOP 源码分析 - 拦截器链的执行过程
1.简介 本篇文章是 AOP 源码分析系列文章的最后一篇文章,在前面的两篇文章中,我分别介绍了 Spring AOP 是如何为目标 bean 筛选合适的通知器,以及如何创建代理对象的过程.现在我们的得 ...
- 5.2 Spring5源码--Spring AOP源码分析二
目标: 1. 什么是AOP, 什么是AspectJ 2. 什么是Spring AOP 3. Spring AOP注解版实现原理 4. Spring AOP切面原理解析 一. 认识AOP及其使用 详见博 ...
随机推荐
- mysql主从同步与防火墙端口的设定
一.背景: 之前做主从同步时,把从库防火墙关了,现在开启防火墙后,从库不同步了 二.解决思路: 1.首先查看了mysql占用的端口,然后开启,tcp/udp都开了,结果还是不行 firewall-cm ...
- easyui学习笔记4—panel的实现
这篇看看easyui是怎么实现panel的,就是类似一个容器,里面可以装具体内容或者其他的easyui控件. 1.这里先看看引用的资源文件 <link rel="stylesheet& ...
- 什么是Github的元数据metadata以及如何备份github上的数据
github被微软收购后,提供的工具种类是越来越多了,大大提高了我们程序员日常工作的效率. 今天我偶然发现,我们可以一键把自己整个github上的数据,不仅仅是代码,还包含每个仓库里创建的issue都 ...
- Cloud Tool 小探索
Google Apps不用多说. Google drive免费提供15GB的容量. Microsoft Windows Live感觉功能上和google相比无亮点和优势. SkyDrive免费提供7G ...
- Perl中的字符串操作函数
1.$position = index(string,substring,skipchars): 该函数返回子串substring在字符串string中的位置,如果不存在,则返回-1:参数skipch ...
- 「uoj#188. 【UR #13】Sanrd」
题目 不是很能看懂题意,其实就是求\([l,r]\)区间内所有数的次大质因子的和 这可真是看起来有点鬼畜啊 这显然不是一个积性函数啊,不要考虑什么特殊的函数了 我们考虑Min_25筛的过程 设\(S( ...
- 跟着大神学Mongo,Mongodb主从复制本机简单操作总结
原文链接:http://www.cnblogs.com/huangxincheng/archive/2012/03/04/2379755.html 本机安装MongoDB不在介绍,本文Mongo小菜鸟 ...
- springboot+mybatis+shiro——shiro简介
转载:[一]shiro入门 之 Shiro简介 一.shiro介绍: 官方网址:http://shiro.apache.org/introduction.html,shiro的功能包括:认证.授权.加 ...
- Haroopad 中文不显示
https://blog.csdn.net/zgf19930504/article/details/51508111 1. 选择文件--> 偏好设置 2. 选择 编辑器--> 编辑--&g ...
- Context initialization failed org.springframework.beans.factory.BeanCreationException
严重: Context initialization failed org.springframework.beans.factory.BeanCreationException: Error cre ...