SPRING07_自动装配如何加强、@Autowired注解debug分析、总结

文章目录

  • ①. Spring启动一行代码:
  • ②. ApplicationContex增强功能
  • ③. 自动装配如何装配进来
  • ④. @Autowired自动注入细节xml版
  • ⑤. @Autowired注解版分析
  • ⑥. 总结一下

①. Spring启动一行代码:

  • ①. 创建一个IOC容器,传入容器的xml配置文件,Spring在整个创建容器的过程中全部都准备好了,接下来就可以拿来用了
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

在这里插入图片描述

  • ②.按照上面的Spring的架构原理图,ResourceReader先来加载Xml配置资源文件,加载来以后交给这些BeanDefinitionReaderBean的读取器来进行读取,这些BeanDefinitionReaderBean的读取器最终再交给BeanDefinitionParserDelegate解析器,来解析Xml配置资源文件中的每一个标签,如果Xml配置资源文件的标签里面是bean标签,说明是要生成一个组件,会为这个bean标签解析成一个BeanDefinition,这个BeanDefinitionbean定义信息就是造飞机的图纸,图纸最终进入档案馆BeanDefinitionRegistry,BeanDefinitionRegistry是一个接口,而真正的档案馆实现叫DefaultListableBeanFactory,DefaultListableBeanFactory档案馆里面最核心的关键点就在于beanDefinitionMap
//所有bean定义信息的集合,按照名字以及对应BeanDefinition关系都保存好了
// 这也解释了spring架构原理里面,spring解析来的所有资源都会存在这个档案馆,这个档案馆就是一个beanDefinitionMap
/** Map of bean definition objects, keyed by bean name. */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
  • ③. 接下来就会看到源码里面会有一个for循环,从方案管里面获取bean定义的名字,挨个进行遍历,来进行获取和创建,这就是创建bean的过程
// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {if (isFactoryBean(beanName)) {Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {FactoryBean<?> factory = (FactoryBean<?>) bean;boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,getAccessControlContext());}else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean<?>) factory).isEagerInit());}if (isEagerInit) {getBean(beanName);}}}else {getBean(beanName);}}
}
  • ④. 整个bean又存储在DefaultSingletonBeanRegistry默认的单实例bean的注册中心,DefaultListableBeanFactory的最终父类还是DefaultSingletonBeanRegistry默认的单实例bean的注册中心,这也是默认的单实例bean中心
    所有的单实例Bean都会在DefaultSingletonBeanRegistry这个里面
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {
  • ⑤. DefaultSingletonBeanRegistry的具体哪个里面呢
  1. 整个Spring的设计都是模板方法模式,父类里面定义了很多方法属性,子类不断的去进行继承,子类来进行功能的增强。在DefaultSingletonBeanRegistry里面其中还有一个关键环节:singletonObjects
//缓存所有单实例bean对象,单例对象池,这也就是ioc容器-单例池
//Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
  1. 每一个对象,都有一个key(String),按照这个key(String)能够查到这个value(object)对象,这个对象就是单例对象池SingletonObjects.这个单例池(SingletonObjects)最终相当于按照图纸要造飞机一个真实的对象,造的飞机就在这个DefaultSingletonBeanRegistry,DefaultSingletonBeanRegistry是飞机的仓库,而DefaultSingletonBeanRegistry这个飞机仓库是DefaultListableBeanFactory这个的一个父类,Spring的底层只会用到DefaultListableBeanFactory这一个类,但这个DefaultListableBeanFactory一个类既是bean定义信息图纸的存储中心,又是DefaultSingletonBeanRegistry飞机的存储中心
  2. 在Spring底层,可以把单例对象池SingletonObjects称为容器,单例对象池SingletonObjects这里面是最常用的,所有的单实例都在单例对象池SingletonObjects这里面放着,所以这就是一个IOC容器
  • ⑥. IOC容器其实在底层就是一个map - singletonObjects,把这些一大堆的组件保存起来,以后若要用,就直接从这个map - singletonObjects进行获取即可,这种设计模式叫享元模式(属于结构型模式)
    享元模式:就是有一些东西后来要经常用,就可以把它池化,放在一个池里面,以后要用到的时候,直接返回它的元对象,享元就是返回元对象,所以这个享元模式就是一个很典型的模式,Spring最终把这些单例的东西放在这个SingletonObjects里面,以后谁要用就返回给谁,这也叫享元模式

  • ⑦. 面试问,IOC容器是个啥?就说是一个享元模式实现的一个单例对象池singletonObjects,原来IOC容器的这个底层最应该关注的其实就是DefaultListableBeanFactory,这个DefaultListableBeanFactory有bean的定义信息,包括有整个Bean的真正实例信息等存在这里

②. ApplicationContex增强功能

  • ①. 一个组件实现了ApplicationContextAware,就只需要准备一个ApplicationContext的Set方法。然后就会利用回调把ioc容器传入过来,这一块就相当于对这个组件的功能增强
/*** Aware接口:装配spring底层的一些组件也就是bean工厂里面的东西*/
@Component
public class Person implements ApplicationContextAware {@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {//利用回调机制,把ioc容器传进来this.context = applicationContext;}
}
  • ②. 一个Person为什么能把ApplicationContex这个ioc容器当为自己的参数传入进来?发现整个探索原理的过程中,Aware是什么时候创建过来的

  • ③. 把档案馆里面每一个bean的名字获取到,然后每一个bean挨个创建

  • ④. 创建的过程中就开始创建相应的对象,在整个相应对象创建完,初始化完了以后,就会执行一个东西叫BeanPostProcessor后置处理器这个东西也叫ApplicationContextAwareProcessor,ApplicationContextAwareProcessor实现了这个BeanPostProcessor后置处理器。

class ApplicationContextAwareProcessor implements BeanPostProcessor {
  • ⑤. 初始化完以后,BeanPostProcessor后置处理器就会有一个执行所有这个处理器的回调,这个处理器执行回调的时候,就会判断当前正在初始化的这个对象,是不是ApplicationContextAware接口

  • ⑥. 如果是这个ApplicationContextAware接口,它就把这个相应的对象,转成这个ApplicationContextAware接口,利用多态调用

  • ⑦. 这个相应的对象转成ApplicationContextAware接口以后,就会调用ApplicationContextAware接口的setApplicationContextApplicationContext applicationContext方法,把ioc容器传进去,提供使用就行了,所以这就相当于自动注入了一个。不过这个对象是通过实现接口的方式进行自动注入的

  • ⑧. 自动注入的这个东西的功能是由BeanPostProcessor后置处理器来进行完成的

③. 自动装配如何装配进来

  • ①. 在Person里面把Car进行自动装配过来,在setCar方法的上面,标注一个@Autowired,相当于setCar方法就会被调用
/*** Aware接口:装配spring底层的一些组件也就是bean工厂里面的东西*/
@Component
public class Person implements ApplicationContextAware,MessageSourceAware {//	@AutowiredApplicationContext context ;  //可以要到ioc容器public ApplicationContext getContext() {return context;}public Person() {System.out.println("person创建....");}private String name;private Cat cat;@Autowiredpublic void setCat(Cat cat) {this.cat = cat;}public String getName() {return name;}public void setName(String name) {this.name = name;}//去容器中找,但是容器中的这个组件,是一个多实例的,所以一旦去了容器中找,// 容器一看这个组件是多实例的,容器就应该给cat再创建一个实例//@Lookup一定要放在get的方法上,因为@Bean的方式注册到容器中,那么@Lookup这个注解就不能用的@Lookuppublic Cat getCat() {return cat;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +'}';}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {//利用回调机制,把ioc容器传进来this.context = applicationContext;}
}
  • ②. 在如下的三个位置打断点:Person默认的无参构造、setCat方法里面、setApplicationContext方法里面
    在这里插入图片描述
  • ③. 可以看到,来到了这个Person对象的创建的构造器
public Person() {System.out.println("person创建....");}
  • ④. 放行后,到了setApplicationContext这个方法。这个方法是因为Person实现了ApplicationContextAware接口执行的,而它整个的执行逻辑就是这样:
  1. 想要创建ioc容器,ioc容器就得调用它自己的三参数的构造方法,然后在关键一步就得刷新它整个容器(refresh) new ClassPathXmlApplicationContext->refresh()
  2. refresh刷新容器的整个过程其实就是挨个进行创建组件,完成初始化,工厂的初始化就是把里面的所有东西都创建好 – finishBeanFactoryInitialization
  3. 创建所有非懒加载的单实例bean—preInstantiateSingletons
//(1). 想要创建ioc容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("xxx.xml");//(2). ioc的三参构造方法
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {this(new String[] {configLocation}, true, null);}(3). 刷新工厂
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {super(parent);setConfigLocations(configLocations);if (refresh) {// 刷新工厂refresh();}
}(4). 完成Bean工厂初始化
refresh方法里面:// Instantiate all remaining (non-lazy-init) singletons.// 完成bean工厂的初始化,所以对象创建是在bean工厂初始化完成的时候干的事finishBeanFactoryInitialization(beanFactory);(5). 初始化所有的非懒加载的单实例bean
finishBeanFactoryInitialization方法里面:// Instantiate all remaining (non-lazy-init) singletons.//初始化所有的非懒加载的单实例beanbeanFactory.preInstantiateSingletons();
  1. 创建的过程就是如果你是工厂bean则执行下边逻辑isFactoryBean下面的逻辑,否则就执行getBean进行普通的单实例非懒加载bean的创建。下面为具体的细节:
preInstantiateSingletons下面的代码// 从档案馆里面获取到所有的bean名称
List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
// Trigger initialization of all non-lazy singleton beans...for (String beanName : beanNames) {RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);// 如果是不是抽象 && 是单列 && 不是懒加载if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {// 如果是FactoryBean,就执行下边逻辑if (isFactoryBean(beanName)) {Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);if (bean instanceof FactoryBean) {FactoryBean<?> factory = (FactoryBean<?>) bean;boolean isEagerInit;if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,getAccessControlContext());}else {isEagerInit = (factory instanceof SmartFactoryBean &&((SmartFactoryBean<?>) factory).isEagerInit());}if (isEagerInit) {getBean(beanName);}}}else {// 若不是FactoryBean,就执行下面这段代码,普通的单实例非懒加载bean的创建// Spring的底层bean第一次没有初始化,也是调用getBean这个方法来对bean进行初始化的getBean(beanName);}}}//---------------------------------------------------------------------
// Implementation of BeanFactory interface
//---------------------------------------------------------------------// getBean()相当于当前要初始化一个普通bean,那初始化这个普通bean就会调用doGetBean来执行这个getBean()方法,这就是一个典型的模板模式
public Object getBean(String name) throws BeansException {return doGetBean(name, null, null, false);
}// doGetBean里面有一个关键的环节叫创建bean的实例
protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException {.....// 创建Bean实例 - Create bean instance.if (mbd.isSingleton()) {// bean实例它就会调用getSingleton方法// getSingleton方法获取单例最核心的一点就是给这个方法里面传当前bean的名字,还传了一个lamdb表达式,而这个getSingleton方法接收的Lambda表达式叫ObjectFactory对象工厂// 这个lamdb表达式相当于定义了一个函数式的接口,相当于Lambda表达式里面的内容就是getObject方法的方法体sharedInstance = getSingleton(beanName,  () -> {try {return createBean(beanName, mbd, args);  //创建bean对象的实例}});}@FunctionalInterface
public interface ObjectFactory<T> {/*** Return an instance (possibly shared or independent)* of the object managed by this factory.* @return the resulting instance* @throws BeansException in case of creation errors*/T getObject() throws BeansException;}public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {........//这里会调用lamda表达式的内容singletonObject = singletonFactory.getObject();
}
  1. 代码核心部分解释
    5.1. createBean的官方注释也说明了,它是提供一个AbstractBeanFactory的实现,也就是这是一个抽象工厂的模板方法,所以这个模板方法模式在Spring底层也用的非常多
    5.2. 它去调用真正的创建beancreateBean的方法,创建beancreateBean的方法是利用doCreateBean方法进行创建的,把bean的名字和bean的定义信息还把一些要用参数传了过来,但此时还没有bean的实例的
    5.3. 整个bean的创建就有一个叫createBeanInstance的方法,这里它想要创建bean实例对象的时候就继续往下走,进入了createBeanInstance这个方法里面
    5.4. 前面进行一大堆判断以后,主要就是为了拿到一个构造器ctors,然后前面若已经有构造器了,它可以用构造器进行自动注入autowireConstructor
    5.5. 若没有这个构造器自动注入autowireConstructor就默认使用无参构造器instantiateBean:初始化bean为当前组件创建对象
AbstractAutowireCapableBeanFactory类下的//---------------------------------------------------------------------
// Implementation of relevant AbstractBeanFactory template methods
//---------------------------------------------------------------------
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args){......try {Object beanInstance = doCreateBean(beanName, mbdToUse, args);if (logger.isTraceEnabled()) {logger.trace("Finished creating instance of bean '" + beanName + "'");}return beanInstance;}
}protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)throws BeanCreationException {......if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);//创建bean的实例}
}protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {.....// Preferred constructors for default construction?ctors = mbd.getPreferredConstructors();if (ctors != null) {return autowireConstructor(beanName, mbd, ctors, null);}// 默认使用无参构造器为当前组件创建对象 No special handling: simply use no-arg constructor.return instantiateBean(beanName, mbd);
  1. 代码核心部分解释
    6.1. 拿到初始化getInstantiationStrategy策略,就调用初始化instantiate方法
    6.2. 初始化instantiate方法,就利用BeanUtils工具使用初始化策略来开始初始化,所以看Spring源码的底层,可以发现非常多的一些工具类。利用工具类将其进行赋值处理
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {try {Object beanInstance;final BeanFactory parent = this;if (System.getSecurityManager() != null) {beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {public Object run() {// 这个初始化策略可以传入很多种初始化策略,一种是SimplelnstantiationStrategy使用JDK反射策略,另外一种是CglibSubclassingInstantiationStrategy使用Cglib创建一个代理对象策略// 拿到初始化getInstantiationStrategy策略,就调用初始化instantiate方法return getInstantiationStrategy().instantiate(mbd, beanName, parent);}}, getAccessControlContext());}else {beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);}BeanWrapper bw = new BeanWrapperImpl(beanInstance);initBeanWrapper(bw);return bw;}catch (Throwable ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);}
}public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {....return BeanUtils.instantiateClass(constructorToUse);}else {// Must generate CGLIB subclass.return instantiateWithMethodInjection(beanDefinition, beanName, owner);}
}
  • ⑦. 经过上面① - ⑥最终相应的对象就创建好了,这就是对象创建,这是利用了初始化策略创建的bean实例。
    相应的对象创建完了以后,那些组件是什么时候进来的?比如setApplicationContext是什么时候进来的?
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {//利用回调机制,把ioc容器传进来this.context = applicationContext;
}protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {// Instantiate the bean.BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) {instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}try {// 把当前bean里面的属性等该复制的复制,这个Bean的移民也就是牵扯到自动装配环节populateBean(beanName, mbd, instanceWrapper);if (exposedObject != null) {// 初始化beanexposedObject = initializeBean(beanName, exposedObject, mbd);}}
  • ⑦. 自动装配环节就是在populateBean这个方法里面,就是属性的赋值,Spring在什么时候搞定的
    所有的bean都要进行以上这么一个大过程-每一个bean无非它要获取这个组件,获取的时候没有的时候就创建,创建完了对象有了接下来就属性赋值,属性赋值完了,就进行各种增强的环节

  • ⑧. 继续来分析:什么时候发生了给相应属性进行赋值?

  1. 对象创建完以后,自然而然要属性赋值的操作,属性赋值就在populateBean这个方法里面
  2. populateBean这个方法前面封装了一个PropertyValues,就是从bean的定义信息里面拿到所有的属性键值对,而且这个PropertyValues还是个迭代器模式
  3. 相当于把当前bean里面有多少个属性,可以利用迭代器进行迭代出来,所以Spring里面又有一个迭代器模式叫PropertyValues,而每一个PropertyValues指的是属性的键值对,键就是属性名,值就是属性值
  4. 把深拷贝deepCopy这个里面的name,value信息拿来给bw,bw就相当于封装好了所有反射逻辑,所以至此这个bw方法一调用,那么底层就是各种反射进行设置值,把pvs这个相当于要赋值的这个玩意要给javabean里面设置过去,如果很多属性的话就是遍历赋值,所以这就是属性赋值过程
// (1). Initialize the bean instance.
Object exposedObject = bean;
try {// 给创建好的对象每个属性进行赋值populateBean(beanName, mbd, instanceWrapper);// 初始化beanexposedObject = initializeBean(beanName, exposedObject, mbd);
}(2). populateBean
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {....// PropertyValues指的是一个属性的键值对,键是属性名,value是属性值PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);....if (pvs != null) {applyPropertyValues(beanName, mbd, bw, pvs);}
}(3). applyPropertyValues
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {....// Set our (possibly massaged) deep copy.try {// 这是一个深拷贝,拷贝真正的值,拷贝所有的值bw.setPropertyValues(new MutablePropertyValues(deepCopy));}catch (BeansException ex) {throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);}(4). 
@Override
public void setPropertyValues(PropertyValues pvs, boolean ignoreUnknown, boolean ignoreInvalid)throws BeansException {for (PropertyValue pv : propertyValues) {setPropertyValue(pv);}

在这里插入图片描述

  • ⑨. 属性赋值了以后接下来还有一个叫初始化beaninitializeBean
(1). populateBean
try {// 给创建好的对象每个属性进行赋值populateBean(beanName, mbd, instanceWrapper);// 初始化beanexposedObject = initializeBean(beanName, exposedObject, mbd);
}(2). applyBeanPostProcessorsBeforeInitialization
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {if (mbd == null || !mbd.isSynthetic()) {wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}
}(3). postProcessBeforeInitialization
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)throws BeansException {Object result = existingBean;for (BeanPostProcessor processor : getBeanPostProcessors()) {// 执行后置处理器逻辑Object current = processor.postProcessBeforeInitialization(result, beanName);if (current == null) {return result;}result = current;}return result;
}(4).invokeAwareInterfaces
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware ||bean instanceof ApplicationStartupAware)) {return bean;}AccessControlContext acc = null;if (System.getSecurityManager() != null) {acc = this.applicationContext.getBeanFactory().getAccessControlContext();}if (acc != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {invokeAwareInterfaces(bean);return null;}, acc);}else {// 执行对应的处理器逻辑invokeAwareInterfaces(bean);}return bean;
}(5). 执行对应的处理器逻辑
private void invokeAwareInterfaces(Object bean) {if (bean instanceof EnvironmentAware) {((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());}if (bean instanceof EmbeddedValueResolverAware) {((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);}if (bean instanceof ResourceLoaderAware) {((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);}if (bean instanceof ApplicationEventPublisherAware) {((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);}if (bean instanceof MessageSourceAware) {((MessageSourceAware) bean).setMessageSource(this.applicationContext);}if (bean instanceof ApplicationStartupAware) {((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());}if (bean instanceof ApplicationContextAware) {((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);}
}

④. @Autowired自动注入细节xml版

理解过程即可

  • ①. 坏境搭建、断点打在setCat方法上面
	<bean class="com.xiaozhi.bean.Cat" id="cat"><property name="name" value="TOMCAT"></property></bean>

在这里插入图片描述

  • ②. 依旧还是那一套原理:还是创建IOC容器,IOC容器创建就调用三参数的构造器,然后要开始刷新工厂,要把所有里面的单实例组件都准备好,创建所有的非懒加载的单实例bean,然后调用getBean(beanName);,也就是每一个组件在容器底层都是调用getBean出来的,然后getBean里面继续doGetBean,然后继续调用lamda表达式的方法,然后前面已经创建好bean对象了…
    在这里插入图片描述

  • ③. 这里通过debug可以看到对应的属性值

在这里插入图片描述

  • ④. 然后在这个环节就挨个遍历,给每一个属性进行赋值。

在这里插入图片描述

  • ⑤, 当前cat要进行赋值,不过这个cat的值,已经拿到了,因为自动装配,它从容器中把这个值找到就行了。
    调用writeMethod.invoke方法属性进行构造,最终还是利用反射调用setCat方法进行赋值
    在这里插入图片描述

⑤. @Autowired注解版分析

  • ①. 断点打在注解的方法里面
    在这里插入图片描述

  • ②. 原来的那一套流程,IOC创建,初始化所有单实例,getBean等一系列操作

  • ③. 来到populateBean(beanName, mbd, instanceWrapper);给创建好的对象属性每个进行赋值
    在这里插入图片描述

  • ④. getBeanPostProcessorCache,相当于把所有的后置处理器的缓存拿来,相当于拿一些后置处理器。其中正在用的这个后置处理器叫AutowiredAnnotationBeanPostProcessor(自动装配注解的bean后置处理器)
    如果是自动装配功能,还会使用一个后置处理器AutowiredAnnotationBeanPostProcessor
    AutowiredAnnotationBeanPostProcessor后置处理器只不过接口叫InstantiationAwareBeanPostProcessor。
    在这里插入图片描述

  • ⑤. AutowiredAnnotationBeanPostProcessor这个后置处理器有了这个对象了,那么这个后置处理器拦截这个对象里面的加了注解的属性,给这些属性进行赋值,所以这也就是增强的拦截功能,在Spring的底层会发现非常多的这些后置处理器,在各个阶段来进行功能的增强

@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {// 找到自动装配的元信息InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);try {metadata.inject(bean, beanName, pvs);}catch (BeanCreationException ex) {throw ex;}catch (Throwable ex) {throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);}return pvs;}
  • ⑥. 找哪些属性或者方法上面使用了自动注入的注解
    找所有属性的@Autowired和@Value,@Inject注解的
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {// Fall back to class name as cache key, for backwards compatibility with custom callers.String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());// Quick check on the concurrent map first, with minimal locking.InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);if (InjectionMetadata.needsRefresh(metadata, clazz)) {synchronized (this.injectionMetadataCache) {metadata = this.injectionMetadataCache.get(cacheKey);if (InjectionMetadata.needsRefresh(metadata, clazz)) {if (metadata != null) {metadata.clear(pvs);}// 下面是分析当前类方法或者属性有没有标注@Autowired等自动赋值的注解metadata = buildAutowiringMetadata(clazz);this.injectionMetadataCache.put(cacheKey, metadata);}}}return metadata;
}
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {return InjectionMetadata.EMPTY;}List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();Class<?> targetClass = clazz;do {final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();// (1). 找所有属性中标注了Autowired注解ReflectionUtils.doWithLocalFields(targetClass, field -> {MergedAnnotation<?> ann = findAutowiredAnnotation(field);if (ann != null) {if (Modifier.isStatic(field.getModifiers())) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation is not supported on static fields: " + field);}return;}boolean required = determineRequiredStatus(ann);currElements.add(new AutowiredFieldElement(field, required));}});// (2). 拿到所有的方法,看看有没有@Autowired注解ReflectionUtils.doWithLocalMethods(targetClass, method -> {Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return;}MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {if (Modifier.isStatic(method.getModifiers())) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation is not supported on static methods: " + method);}return;}if (method.getParameterCount() == 0) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation should only be used on methods with parameters: " +method);}}boolean required = determineRequiredStatus(ann);PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);currElements.add(new AutowiredMethodElement(method, required, pd));}});// 所有准备好的元素返回给我们elements.addAll(0, currElements);targetClass = targetClass.getSuperclass();}while (targetClass != null && targetClass != Object.class);return InjectionMetadata.forElements(elements, clazz);
}
@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {MergedAnnotations annotations = MergedAnnotations.from(ao);for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {MergedAnnotation<?> annotation = annotations.get(type);if (annotation.isPresent()) {return annotation;}}return null;
}
public AutowiredAnnotationBeanPostProcessor() {this.autowiredAnnotationTypes.add(Autowired.class);this.autowiredAnnotationTypes.add(Value.class);try {this.autowiredAnnotationTypes.add((Class<? extends Annotation>)ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");}catch (ClassNotFoundException ex) {// JSR-330 API not available - simply skip.}
}
  • ⑦. 就是说它先找属性,再找方法看有没有标注@Autowired注解的。只要找到了就加入到元素里面,最终所有都找到以后,把所有的这些元素elements进行返回,一返回以后,就相当于要@Autowired自动装配的东西
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Collection<InjectedElement> checkedElements = this.checkedElements;Collection<InjectedElement> elementsToIterate =(checkedElements != null ? checkedElements : this.injectedElements);if (!elementsToIterate.isEmpty()) {for (InjectedElement element : elementsToIterate) {element.inject(target, beanName, pvs);}}
}
  • ⑧. 最后利用反射赋值就来到了setCat方法
    在这里插入图片描述

⑥. 总结一下

Spring的底层通过后置增强机制来完成很多功能,所有后来的核心功能,比如切面,比如事务,比如代理,日志等一大堆,一个注解就能够搞定的事情,这到底它是怎么完成的?所以要分析Spring的一个功能的时候,主要分析两点就行了:
1. 这个功能Spring在启动的时候注入了什么组件?比如想做事务相关,Spring在启动就会准备一个事务的TransactionManager事务管理器
2. 这个功能牵扯到的组件在什么位置被什么后置增强器增强成了什么样子

这是复习回顾顺便研究了一下BeanPostProcessor后置处理器整个强大之处,BeanPostProcessor翻译过来就是bean的后置处理器,它就是在一个bean的初始化前后进行的功能增强的作用,但是这个BeanPostProcessor处理器有很多的子接口,所有这些个后置处理器何时进行了增强,就是Spring源码之后置处理器的接口关系和Spring源码之工厂的后置处理&配置类处理以及Spring源码之bean后置处理器的创建过程研究的重点,如果把这些研究好了,那么在后来分析Spring的任何功能也就非常简单了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/398148.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

日期类比较大小和加减

日期比较大小 先定义一个日期类&#xff0c;这里包含年月日&#xff0c;这里头文件和源文件分离 重载符号 1.operator> 先声明函数 这里大于可以把*this> d 的情况全部列举出来 bool date::operator>(const date& d) {if (_year > d._year){return true;}e…

总要去趟沙漠吧:中卫沙坡头

周五 下班出发 西安 -> 固原 周六 疯狂的一天 陕甘宁蒙 沙坡头 集大漠、黄河、高山、绿洲为一处&#xff0c;具西北风光之雄奇&#xff0c;兼江南景色之秀美。有中国最大的天然滑沙场&#xff0c;有横跨黄河的“天下黄河第一索”&#xff0c;有黄河文化代表古老水车&#…

观测云突变告警,精准预测云原生的系统异常

背景 观测云 DataKit 是一个强大的数据采集工具&#xff0c;能够收集和监控容器化环境和 Kubernetes 集群的指标、对象和日志数据。通过灵活使用 DataKit 收集的数据&#xff0c;可以对 Kubernetes 集群进行深入的监控和分析&#xff0c;从而实现更好的运维和优化。以下是一些…

FRTIMP_YTFRB_WEB

FRTIMP_YTFRB_WEB 林业资源交易信息管理平台

Docker相关配置记录

Docker相关配置记录 换源 {"registry-mirrors": ["https://dockerhub.icu","https://docker.chenby.cn","https://docker.1panel.live","https://docker.awsl9527.cn","https://docker.anyhub.us.kg","htt…

网络通信之套接字

TCP服务端代码实现 #include<myhead.h> #define SER_POST 6666 //服务器端口 #define SER_IP "192.168.36.172"//服务器ip int main(int argc, const char *argv[]) {//1.创建套接字int sfd socket(AF_INET,SOCK_STREAM,0);//参数1&#xff1a;通信域//参数2…

零基础5分钟学会谷歌云GCP核心云架构技能 - 成本分析篇

简介&#xff1a; 欢迎来到小李哥谷歌云GCP云计算知识学习系列&#xff0c;适用于任何无云计算或者谷歌云技术背景的开发者&#xff0c;让大家零基础5分钟通过这篇文章就能完全学会谷歌云一个经典的服务开发架构方案。 我将每天介绍一个基于全球三大云计算平台&#xff08;AW…

AI赋能周界安防:智能视频分析技术构建无懈可击的安全防线

周界安全防范是保护机场、电站、油库、监狱、工业园区等关键设施免受非法入侵和破坏的重要措施。传统的周界安防手段主要依靠人员巡查和物理屏障&#xff0c;但这种方式不仅人力成本高&#xff0c;而且效率较低&#xff0c;难以满足日益复杂多变的安全需求。随着AI技术的引入&a…

windows10和linux(debian12)设置静态ip————附带详细过程

文章目录 0 背景1 linux&#xff08;debian&#xff09;1.1 查看网络配置1.2 获取ip动态分配下的配置1.3 打开网络配置文件1.4 重新启动网络服务1.5 验证设置 2 windows2.1 查看自动获取ip地址下的配置2.2 进行设置 0 背景 因为下位机只能获取固定的ip&#xff08;ip池很小&am…

QT自定义系统快捷键任务

关键代码 //自定义快捷键检测 connect(this->ui->hotkeySequenceEdit_1, &QKeySequenceEdit::keySequenceChanged,this, &HotTestWidget::setShortcut_1);// 托盘显示 trayIcon new QSystemTrayIcon(this); QPixmap pixmap("tray.png"); QIcon icon(…

【网络】IP和MAC地址的映射——ARP协议和ARP欺骗概述

目录 引言 ARP的工作机制 ARP欺骗 ARP欺骗的断网行为 ARP欺骗成为中间人 工具介绍 个人主页&#xff1a;东洛的克莱斯韦克-CSDN博客 引言 同一子网内不同主机用数据链路层的MAC地址来寻址&#xff0c;而不是子网内的私有IP&#xff08;网络层&#xff09;。数据包中的IP…

JDBC如何避免SQL注入

JDBC如何避免SQL注入 一 . 什么是SQL注入 SQL注入&#xff08;SQL Injection&#xff09;是一种代码注入技术&#xff0c;它允许攻击者将或“注入”恶意的SQL命令到后端数据库引擎执行。这些恶意的SQL命令可以执行未授权的数据库查询、修改数据、管理数据库服务器上的文件系统…

三级_网络技术_20_路由器的配置及使用

1.封禁ICMP协议&#xff0c;只转发212.78.170.166/27所在子网的所有站点的ICMP数据包&#xff0c;正确的access-list配置是()。 Router (config)#access-list 110 permit icmp 212.78.170.166 0.0.0.0 any Router (config)#access-list 110 deny icmp any any Router (confi…

day2-网络连接网卡配置原理

1.window网卡 理解&#xff1a; window 有 2 块网卡 本地网卡 192.168.13.253 用于连接外网 vmnet8 10.0.0.1(装虚拟机自动生成的 如果没有自动生成…) 虚拟机添加 2 块网卡&#xff1a; 第一块网卡 NAT 模式 添加网卡的时候设置 NAT 模式 2 个作用&#xff0c;用于连接 wi…

C++_继承

继承 基础认识 像模板是函数和类代码的复用&#xff0c;而继承是对类代码的复用&#xff0c;都是更多的把复杂的任务交给编译器处理。 使用方法 继承的方式 class的默认继承方式是private&#xff0c;struct的默认继承方式是public&#xff0c;但还是最好加上。 protected成…

C++ 函数模板和类模板

参考视频&#xff1a;C类模板_哔哩哔哩_bilibili 遗留问题&#xff1a;编译器怎么处理函数模板和类模板 目录 一、为什么会有函数模版&#xff1f;函数模板是为了解决什么问题&#xff1f; 二、函数模板的概念 三、函数模版的使用 四、函数模板的特化 五、类模板的概念 …

基于ssm+vue+uniapp的英语学习交流平台小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

排序算法之桶排序

title: 桶排序 date: 2024-7-25 18:58:19 0800 categories: 排序算法 tags:排序算法桶排序 description: 桶排序&#xff08;bucket sort&#xff09;是分治策略的一个典型应用。它通过设置一些具有大小顺序的桶&#xff0c;每个桶对应一个数据范围&#xff0c;将数据平均分配…

Qt—Qtcreator中自定义类时,下拉菜单中没有出现要继承的Qt类

问题描述&#xff1a;Qtcreator中自定义类时&#xff0c;下拉菜单中没有出现要继承的Qt类 这里我想要继承 QLineEdit 类&#xff0c;但是在这个下拉菜单中没有找到 我认为这个是qtcreator版本的问题&#xff0c;因为我直接去 #include 是可以找到这个类的 直接创建出来的类中…

Python Flask 与 Node.js Express

我的新书《Android App开发入门与实战》已于2020年8月由人民邮电出版社出版&#xff0c;欢迎购买。点击进入详情 构建 Web 应用程序时&#xff0c;选择正确的框架对于性能和可扩展性至关重要。Python 的 Flask 和 Node.js 的 Express 是两种流行的选择&#xff0c;它们根据项目…