共计 6505 个字符,预计需要花费 17 分钟才能阅读完成。
前言
熟练掌握
这个词置信很多同行在写简历的时候都用到过。熟练掌握
这四个字是依据每个人程度不一样,了解也不一样。比方一个刚毕业的大学生,他可能也会在简历外面写 熟练掌握 spring 框架
,但实际上他并没有看过 spring 源码,也没有太多实际。可能只是看了几本书,应用spring 框架
写了一个毕业设计,而后就说本人 熟练掌握 spring 框架
了。再比方一个有二三年工作教训的求职者,也在简历外面说本人 熟练掌握 spring 框架
,他的理由是他看过 spring 的一些关键性代码了,也在理论工作中应用 spring 开发了工程项目。甚至本人依据一些业务须要,写了几个不错的针对 spring 框架的扩大。再比方一个工作了四五年的程序员,他在本人简历上写 熟练掌握 spring 框架
。因为他把 spring 和 spring boot 源码大部分都看过,工作中解决了不少波及原理性的问题。对 spring 框架的整个架构图,根本了然于胸。另外总结出了十分多的 spring 相干的最佳实际。再比方一个工作了七八年的程序员,他们对spring
的了解可能又不太一样。其实我想说的是,程度和教训决定了一个人的见解。每个人都应该虚心学习丰盛和坚固本人的常识体系,拓宽常识的广度,增强常识的深度。这样才会在无限的工夫外面,成长成参天大树。好了,废话不多说,明天的主题是 熟练掌握 spring 框架
。那么我就从 n 个问题着手。说一下工作了 n 年的我对 熟练掌握
的见解吧。
BeanFactory 和 FactoryBean 的区别
首先说下 BeanFactory
他是 springIOC 容器的顶层接口。负责管理和生产 Bean。他的默认实现是:DefaultListableBeanFactory
。在 spring boot 我的项目启动时,执行 createApplicationContext()
后返回的实例类型是 AnnotationConfigApplicationContext
,能够看下该类的层次结构图。发现他也是BeanFactory
接口的实现类。代码是在 ApplicationContext
的抽象类 AbstractApplicationContext
中,能够看出所有 BeanFactory
的实现还是调用了 GenericApplicationContext
的成员DefaultListableBeanFactory beanFactory
的具体实现。所以 Bean 治理的外围代码天然就是DefaultListableBeanFactory
。
查看它的类层次结构图发现,这个类次要表演两个角色,第一个就是 bean 工厂,第二个就是 BeanDefinition
的注册核心。bean 工厂提供了对单例 bean 注册核心(DefaultSingletonBeanRegistry
),FactoryBean
注册核心(FactoryBeanRegistrySupport
)的反对。首先咱们看下他是如何实现 bean 工厂的。
注册单例bean
应用 @Component 注解
定义一个UserService
断点设置在 DefaultSingletonBeanRegistry
单例 bean 注册核心的 addSingleton
中。
看下调用栈:
- 产生在
refreshContext
阶段 - 对单例模式 bean 进行初始化
- 通过 getBean 触发实例化
userService
,getBean 进而调用doGetBean
doGetBean
办法能够略微开展下
它调用了 DefaultSingletonBeanRegistry
的getSingleton
其中第二个参数就是 ObjectFactory
,创立 bean 的工厂ObjectFactory
理论调用的是AbstractAutowireCapableBeanFactory
的createBean
办法,进而调用它的 doCreateBean
,接着调用createBeanInstance
办法,进而调用 instantiateBean
办法,应用SimpleInstantiationStrategy
策略类(理论应用的 java 反射技术动静创建对象)创立实例。
获取单例bean
还是方才那个例子。在 ApplicationRunner
的 run 办法调用 getBean
办法。
在 doGetBean
办法里会首先检查单利缓存外面是否有,如果有的话,间接返回。
BeanDefinition
注册
咱们再来看下 BeanDefinition
注册核心是如何实现的。
咱们依然是在 DefaultListableBeanFactory
的registerBeanDefinition
设置断点,看下调用栈。
- 同样产生在
refreshContext
阶段 - 执行所有的
BeanFactoryPostProcessor
- 执行所有的
BeanDefinitionRegistryPostProcessor
,此处默认就一个名为:ConfigurationClassPostProcessor
- 此办法次要工作就是首先调用
ConfigurationClassUtils.checkConfigurationClassCandidate
找到所有ConfigurationClass
的候选人,而后应用ConfigurationClassParser
解析每个ConfigurationClass
。 - 如果是
ComponentScans
的ConfigurationClass
,就调用ClassPathBeanDefinitionScanner
的doScan
进行扫描。 - 将扫描的
BeanDefinition
增加到DefaultListableBeanFactory
的beanDefinitionMap
里。至此实现BeanDefinition
的注册。
FactoryBean
说了这么多,置信读者对 spring
框架的 BeanFactory
有了一个比拟全面的理解了。上面聊聊 FactoryBean
。FactoryBean
是 spring 容器里的一种非凡的bean
。
该接口的实现以
BeanFactory
为工厂。假如某个Bean
实现了该接口,它用作生产对象的工厂。而不是像一般的Bean
那样间接裸露本人。通常应用getObject
办法裸露bean
,FactoryBean
反对单例和原型,并且能够能够按需提早或者在启动的时候创建对象。这个接口在 spring 框架外部大量应用,比方AOP
的org.springframework.aop.framework.ProxyFactoryBean
jpa
的org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean
,然而在理论业务代码外面并不常见。起源 java doc
上面就以 JpaRepositoryFactoryBean
具体介绍下 FactoryBean
是如何工作的。
读者能够翻看下之前的一篇文章【JpaRepositoryBean 创立流程剖析】此处对于 repository
bean 的初始化就不具体介绍了。咱们还是在ApplicationRunner
的 run 办法里调用 ApplicationContext
的getBean
获取一个UserRepository
,如果是第一次获取,流程是这样的。
- 调用
BeanFactory
的getBean
办法。 - 理论逻辑在
AbstractBeanFactory
的doGetBean
办法里。 - 依据 beanName
userRepository
在SingletonBeanRegistry
里找到相应的JpaRepositoryFactoryBean
- 而后依据在
FactoryBeanRegistry
的缓存里(factoryBeanObjectCache
)依据 beanName 查找userRepository
,因为是第一次,所以找不到。 - 调用
FactoryBeanRegistrySupport
的getObjectFromFactoryBean
办法。该办法有个同步代码块,目标是保障并发状况下,创立的对象依然是单例的。 - 同步代码块里回去调用
JpaRepositoryFactoryBean
的getObject
办法获取之前就曾经创立好的repository
,而后退出到factoryBeanObjectCache
中去并返回相应的bean
小结
通过源码学习,咱们发现 BeanFactory
和FactoryBean
是两个齐全不同的概念,然而他们的代码又是严密关联的。FactoryBean
是 BeanFactory
里的一种非凡 bean
, 因为他自身也是一个工厂,能够生产本人的Bean
,有个非凡的中央须要咱们留神一下。如果传入的beanName
是以 &
为前缀的话。会调用 BeanFactoryUtils
的transformedBeanName
办法,去掉前缀,而后在 Singleton 注册核心获取相应的bean
。如果找不到的话会有很长的一段代码进行解决。这里就不做深入探讨了,感兴趣的读者能够钻研下。
BeanPostProcessor 和 BeanFactoryPostProcessor
两个类都以 PostProcessor
结尾,中文名为后置处理器,意思就在 Bean
创立或者 BeanFactory
创立之后进行的操作。spring 外围代码外面 PostProcessor
随处可见。
首先咱们来看下 BeanFactoryPostProcessor
,来张 UML 图。这个图很简略,BeanFactoryPostProcessor
定义了一个办法。参数就是刚刚创立的 bean 工厂。而 BeanDefinitionRegistryPostProcessor
定义的办法,参数就是刚刚创立好的 BeanDefinition
注册核心。
咱们以一个最具备代表性的类 ConfigurationClassPostProcessor
看下它是何时调用的,它做了什么。咱们将断点设置在它的postProcessBeanFactory
和postProcessBeanDefinitionRegistry
办法里。发现产生在 spring 启动的 refreshContext
阶段,此时 Bean 工厂曾经创立了。先调用所有的 BeanDefinitionRegistryPostProcessor
再调用所有 BeanFactoryPostProcessor
。详见PostProcessorRegistrationDelegate
的invokeBeanFactoryPostProcessors
。ConfigurationClassPostProcessor
两次都会被调到。
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {int registryId = System.identityHashCode(registry);
if (this.registriesPostProcessed.contains(registryId)) {
throw new IllegalStateException("postProcessBeanDefinitionRegistry already called on this post-processor against" + registry);
}
if (this.factoriesPostProcessed.contains(registryId)) {
throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against" + registry);
}
this.registriesPostProcessed.add(registryId);
// 外围逻辑在 processConfigBeanDefinition()办法中,用来解决 BeanDefinition 的注册
processConfigBeanDefinitions(registry);
}
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against" + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
// BeanDefinitionRegistryPostProcessor hook apparently not supported...
// Simply call processConfigurationClasses lazily at this point then.
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
// 对加了 @Configuration 注解的配置类进行 Cglib 加强代理
enhanceConfigurationClasses(beanFactory);
// 增加一个 BeanPostProcessor 后置处理器
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
ConfigurationClassPostProcessor
无疑是 spring 中最重要也是最简单的后置处理器了,此处就不具体开展了。再来看下 BeanPostProcessor
的 UML 图。
这两个办法调用的中央都是在 AbstractAutowireCapableBeanFactory
的initializeBean
中。
看个简略的例子吧,下面学习 ConfigurationClassPostProcessor
时,咱们发现它增加了一个 bean 后置处理器 ImportAwareBeanPostProcessor
,上面是它的postProcessBeforeInitialization
办法
// 如果 bean 实现了 ImportAware 接口,就调用一下它的 setImportMetadata 办法,通过这种形式,能够在程序中拿到注解的元数据。public Object postProcessBeforeInitialization(Object bean, String beanName) {if (bean instanceof ImportAware) {ImportRegistry ir = this.beanFactory.getBean(IMPORT_REGISTRY_BEAN_NAME, ImportRegistry.class);
AnnotationMetadata importingClass = ir.getImportingClassFor(ClassUtils.getUserClass(bean).getName());
if (importingClass != null) {((ImportAware) bean).setImportMetadata(importingClass);
}
}
return bean;
}
下面是 spring 内置的一个处理器。理论工作中,咱们也会常常自定义后置处理器。一个常见的场景就是对某些类进行动静加强。
未完待续,更多内容请关注【熟练掌握 spring 框架】第二篇