熟练掌握
这个词相信很多同行在写简历的时候都用到过。熟练掌握
这四个字是根据每个人水平不一样,理解也不一样。比如一个刚毕业的大学生,他可能也会在简历里面写熟练掌握spring框架
,但实际上他并没有看过spring源码,也没有太多实践。可能只是看了几本书,使用spring框架
写了一个毕业设计,然后就说自己熟练掌握spring框架
了。再比如一个有二三年工作经验的求职者,也在简历里面说自己熟练掌握spring框架
,他的理由是他看过spring 的一些关键性代码了,也在实际工作中使用spring开发了工程项目。甚至自己根据一些业务需要,写了几个不错的针对spring框架的扩展。再比如一个工作了四五年的程序员,他在自己简历上写熟练掌握spring框架
。因为他把spring和spring boot源码大部分都看过,工作中解决了不少涉及原理性的问题。对spring框架的整个架构图,基本了然于胸。另外总结出了非常多的spring相关的最佳实践。再比如一个工作了七八年的程序员,他们对spring
的理解可能又不太一样。其实我想说的是,水平和经验决定了一个人的见解。每个人都应该虚心学习丰富和巩固自己的知识体系,拓宽知识的广度,加强知识的深度。这样才会在有限的时间里面,成长成参天大树。好了,废话不多说,今天的主题是熟练掌握spring框架
。那么我就从n个问题着手。说一下工作了n年的我对熟练掌握
的见解吧。
首先说下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
阶段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
的注册。说了这么多,相信读者对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
方法里。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
。如果找不到的话会有很长的一段代码进行处理。这里就不做深入探讨了,感兴趣的读者可以研究下。
两个类都以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框架】第二篇
原文:https://www.cnblogs.com/warming666/p/14731408.html