一篇文章让你吃透spring aop底层原理

本文详细解析了Spring框架中自动装配BeanFactory的过程,重点关注了AbstractAdvisorAutoProxyCreator和AnnotationAwareAspectJAutoProxyCreator的初始化方法,以及BeanPostProcessor在Bean创建过程中的角色,包括JDK和Cglib动态代理的运用。
摘要由CSDN通过智能技术生成

2)关注自动装配BeanFactory。

通过代码查看,发现父类AbstractAutoProxyCreator中有后置处理器的内容;AbstactAdvisorAutoProxyCreator类中重写了其父类AbstractAutoProxyCreator中setBeanFactory()方法,在AnnotationAwareAspectJAutoProxyCreator类中initBeanFactory()方法完成了自动装配BeanFactory。分别在这两处关注点打断点来查看其流程:

我们知道AbstactAdvisorAutoProxyCreator 初始化时的一个大致过程如下:

setBeanFactory方法和BeanPostProcessorsBeforeInitialization BeanPostProcessorsAfterInitialization 顺序如下图

源码逻辑:

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {

  if (System.getSecurityManager() != null) {
  	AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
  		invokeAwareMethods(beanName, bean);
  		return null;
  	}, getAccessControlContext());
  }
  else {

// 执行aware 中的方法

  	invokeAwareMethods(beanName, bean);
  }
  Object wrappedBean = bean;
  if (mbd == null || !mbd.isSynthetic()) {
  	//BeanPostProcessor Before方法
  	wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  }
  try {
  	// init 方法 @PostConstruct init指定方法 InitializingBean等方式
  	invokeInitMethods(beanName, wrappedBean, mbd);
  }
  catch (Throwable ex) {
  	throw new BeanCreationException(
  			(mbd != null ? mbd.getResourceDescription() : null),
  			beanName, "Invocation of init method failed", ex);
  }
  if (mbd == null || !mbd.isSynthetic()) {
  	//beanPostProcessor after方法
  	wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  }
  return wrappedBean;

}

invokeAwareMethods


该方法比较简单:

org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator#setBeanFactory

@Override

public void setBeanFactory(BeanFactory beanFactory) {

  super.setBeanFactory(beanFactory);
  if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
  	throw new IllegalArgumentException(
  			"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
  }
  initBeanFactory((ConfigurableListableBeanFactory) beanFactory);

}

protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {

  this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);

}

子类重写了initBeanFactory方法

@Override

protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {

  super.initBeanFactory(beanFactory);
  if (this.aspectJAdvisorFactory == null) {
  	this.aspectJAdvisorFactory = new ReflectiveAspectJAdvisorFactory(beanFactory);
  }
  this.aspectJAdvisorsBuilder =
  		new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);

}

applyBeanPostProcessorsBeforeInitialization


我看的5.3.x版本的spring 开始没重写 这个before方法

invokeInitMethods


实例化

applyBeanPostProcessorsAfterInitialization


此时看beanpostProcessor 工作原理

1)、传入配置类,创建ioc容器

      2)、注册配置类,调用refresh()刷新容器;
      3)、registerBeanPostProcessors(beanFactory);注册bean的后置处理器来方便拦截bean的创建;
          1)、先获取ioc容器已经定义了的需要创建对象的所有BeanPostProcessor
          2)、给容器中加别的BeanPostProcessor
          3)、优先注册实现了PriorityOrdered接口的BeanPostProcessor;
          4)、再给容器中注册实现了Ordered接口的BeanPostProcessor;
          5)、注册没实现优先级接口的BeanPostProcessor;
          6)、注册BeanPostProcessor,实际上就是创建BeanPostProcessor对象,保存在容器中;
              创建internalAutoProxyCreator的BeanPostProcessor【AnnotationAwareAspectJAutoProxyCreator】
              1)、创建Bean的实例
              2)、populateBean;给bean的各种属性赋值
              3)、initializeBean:初始化bean;
                      1)、invokeAwareMethods():处理Aware接口的方法回调
                      2)、applyBeanPostProcessorsBeforeInitialization():应用后置处理器的postProcessBeforeInitialization()
                      3)、invokeInitMethods();执行自定义的初始化方法
                      4)、applyBeanPostProcessorsAfterInitialization();执行后置处理器的postProcessAfterInitialization();
              4)、BeanPostProcessor(AnnotationAwareAspectJAutoProxyCreator)创建成功;--》aspectJAdvisorsBuilder
          7)、把BeanPostProcessor注册到BeanFactory中;
              beanFactory.addBeanPostProcessor(postProcessor);  =======以上是创建和注册AnnotationAwareAspectJAutoProxyCreator的过程========

aop创建对象原理


从上面我分析的逻辑和前置知识非常清楚,当我们自己编写的类填写@EnableAspectJAutoProxy或者通过其他方式开启aop都是在docreateBean方法中进行增强:

我们在这个方法入口打断点 使用断点的方式进行跟踪分析:

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#initializeBean(java.lang.String, java.lang.Object, org.springframework.beans.factory.support.RootBeanDefinition)

exposedObject = initializeBean(beanName, exposedObject, mbd);

这个方法上面我都分析了aware相关的方法, before init after方法,由于 自己的类非aware ,因此不会执行, before没有重写, 因此不重要下面直接after方法

进来的时候实体对象不是代理对象,我们继续往下看从哪里开始处理成的代理对象的

beanpostProcessor 工作原理


从上面分析我们可以知道Spring入住了AnnotationAwareAspectJAutoProxyCreator 一个BeanPostProcessor类,又知道改类没有重写before方法,因此after方法才是我们的重点:

重写 beanpostprocessor的after方法

org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#postProcessAfterInitialization

@Override

public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {

  if (bean != null) {
  	Object cacheKey = getCacheKey(bean.getClass(), beanName);
  	if (this.earlyProxyReferences.remove(cacheKey) != bean) {
  		return wrapIfNecessary(bean, beanName, cacheKey);
  	}
  }
  return bean;

}

这个地方是二级缓存中存在,删除进行创建对象,ps:二级缓存中存放的是只进行实例化,没有进行初始化的对象

postProcessAfterInitialization方法会对切面进行一次包装的处理。

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));
  	this.proxyTypes.put(cacheKey, proxy.getClass());
  	return proxy;
  }
  this.advisedBeans.put(cacheKey, Boolean.FALSE);
  return bean;

}

下面进行创建代理对象

第一步:创建代理对象的ProxyFactory 工厂

第二步:使用工厂模式创建代理对象

protected Object createProxy(Class<?> beanClass, @Nullable String beanName,

  	@Nullable Object\[\] specificInterceptors, TargetSource targetSource) {
  if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
  	AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
  }
  ProxyFactory proxyFactory = new ProxyFactory();
  proxyFactory.copyFrom(this);
  if (proxyFactory.isProxyTargetClass()) {
  	// Explicit handling of JDK proxy targets (for introduction advice scenarios)
  	if (Proxy.isProxyClass(beanClass)) {
  		// Must allow for introductions; can't just set interfaces to the proxy's interfaces only.
  		for (Class<?> ifc : beanClass.getInterfaces()) {
  			proxyFactory.addInterface(ifc);
  		}
  	}
  }
  else {
  	// No proxyTargetClass flag enforced, let's apply our default checks...
  	if (shouldProxyTargetClass(beanClass, beanName)) {
  		proxyFactory.setProxyTargetClass(true);
  	}
  	else {
  		evaluateProxyInterfaces(beanClass, proxyFactory);
  	}
  }
  Advisor\[\] advisors = buildAdvisors(beanName, specificInterceptors);
  proxyFactory.addAdvisors(advisors);
  proxyFactory.setTargetSource(targetSource);
  customizeProxyFactory(proxyFactory);
  proxyFactory.setFrozen(this.freezeProxy);
  if (advisorsPreFiltered()) {
  	proxyFactory.setPreFiltered(true);
  }
  // Use original ClassLoader if bean class not locally loaded in overriding class loader
  ClassLoader classLoader = getProxyClassLoader();
  if (classLoader instanceof SmartClassLoader && classLoader != beanClass.getClassLoader()) {
  	classLoader = ((SmartClassLoader) classLoader).getOriginalClassLoader();
  }
  return proxyFactory.getProxy(classLoader);

}

proxyFactory 工厂拿到了目标对象和定义的切点信息 封装放到这个对象Advisor

我们细看创建代理对象的过程,发现在创建之前首先会根据切入点表达式对增强器进行一一匹配,最终拿到所有的增强器。

创建代理对象:

我们又知道spring创建代理对象有两种方式:jdk动态代理和cglib动态代理

public Object getProxy(@Nullable ClassLoader classLoader) {

  return createAopProxy().getProxy(classLoader);

}

spring 是通过AdvisedSupport 类获取当前用户配置的方式,spring默认使用cglib动态代理

@Override

public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {

  if (!NativeDetector.inNativeImage() &&
  		(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
  	Class<?> targetClass = config.getTargetClass();
  	if (targetClass == null) {
  		throw new AopConfigException("TargetSource cannot determine target class: " +
  				"Either an interface or a target is required for proxy creation.");
  	}
  	//如果目标类是接口或者代理类 使用jdk代理
  	if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
  		return new JdkDynamicAopProxy(config);
  	}
  	return new ObjenesisCglibAopProxy(config);
  }
  else {
  	return new JdkDynamicAopProxy(config);
  }

}

真正获取代理对象的地方cglib代理方式

org.springframework.aop.framework.CglibAopProxy#getProxy(java.lang.ClassLoader)

//根据目标对象获取一堆拦截器

//这就是给代理对象增强的核心代码

Callback[] callbacks = getCallbacks(rootClass);

Callback[] callbacks = getCallbacks(rootClass);

这个地方先混个眼熟,到调用方法时会使用这些拦截器

上面我们就把代理类生产了并且放到容器beanmap里面了

其中生产的过程自己断点看看吧 这个地方我们只看了一个cglib方式生产,底层使用的asm 比较复杂,这里就不再赘述.

调用方法


获取该对象看看代理对象中包含很多拦截器因此先进拦截器中

这个时候拦截器就起作用了直接进入下面的方法

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后的内容

在开头跟大家分享的时候我就说,面试我是没有做好准备的,全靠平时的积累,确实有点临时抱佛脚了,以至于我自己还是挺懊恼的。(准备好了或许可以拿个40k,没做准备只有30k+,你们懂那种感觉吗)

如何准备面试?

1、前期铺垫(技术沉积)

程序员面试其实是对于技术的一次摸底考试,你的技术牛逼,那你就是大爷。大厂对于技术的要求主要体现在:基础,原理,深入研究源码,广度,实战五个方面,也只有将原理理论结合实战才能把技术点吃透。

下面是我会看的一些资料笔记,希望能帮助大家由浅入深,由点到面的学习Java,应对大厂面试官的灵魂追问

这部分内容过多,小编只贴出部分内容展示给大家了,见谅见谅!

  • Java程序员必看《Java开发核心笔记(华山版)》

  • Redis学习笔记

  • Java并发编程学习笔记

四部分,详细拆分并发编程——并发编程+模式篇+应用篇+原理篇

  • Java程序员必看书籍《深入理解 ava虚拟机第3版》(pdf版)

  • 大厂面试必问——数据结构与算法汇集笔记

其他像Spring,SpringBoot,SpringCloud,SpringCloudAlibaba,Dubbo,Zookeeper,Kafka,RocketMQ,RabbitMQ,Netty,MySQL,Docker,K8s等等我都整理好,这里就不一一展示了。

2、狂刷面试题

技术主要是体现在平时的积累实用,面试前准备两个月的时间再好好复习一遍,紧接着就可以刷面试题了,下面这些面试题都是小编精心整理的,贴给大家看看。

①大厂高频45道笔试题(智商题)

②BAT大厂面试总结(部分内容截图)

③面试总结

3、结合实际,修改简历

程序员的简历一定要多下一些功夫,尤其是对一些字眼要再三斟酌,如“精通、熟悉、了解”这三者的区别一定要区分清楚,否则就是在给自己挖坑了。当然不会包装,我可以将我的简历给你参考参考,如果还不够,那下面这些简历模板任你挑选:

以上分享,希望大家可以在金三银四跳槽季找到一份好工作,但千万也记住,技术一定是平时工作种累计或者自学(或报班跟着老师学)通过实战累计的,千万不要临时抱佛脚。

另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
的时间再好好复习一遍,紧接着就可以刷面试题了,下面这些面试题都是小编精心整理的,贴给大家看看。

①大厂高频45道笔试题(智商题)

[外链图片转存中…(img-1LOWbjmN-1713566818929)]

②BAT大厂面试总结(部分内容截图)

[外链图片转存中…(img-Npi2Subk-1713566818931)]

[外链图片转存中…(img-4Opowta9-1713566818934)]

③面试总结

[外链图片转存中…(img-g2pqcxef-1713566818936)]

[外链图片转存中…(img-nCjaKLyd-1713566818937)]

3、结合实际,修改简历

程序员的简历一定要多下一些功夫,尤其是对一些字眼要再三斟酌,如“精通、熟悉、了解”这三者的区别一定要区分清楚,否则就是在给自己挖坑了。当然不会包装,我可以将我的简历给你参考参考,如果还不够,那下面这些简历模板任你挑选:

[外链图片转存中…(img-Y6dFjTCc-1713566818939)]

以上分享,希望大家可以在金三银四跳槽季找到一份好工作,但千万也记住,技术一定是平时工作种累计或者自学(或报班跟着老师学)通过实战累计的,千万不要临时抱佛脚。

另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 11
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值