程序入口:
接着上一篇博客中看完了在AnnotationConfigApplicationContext
的构造函数中的register(annotatedClasses);
将我们传递进来的主配置类添加进了BeanFactory
, 本片博客继续跟进refresh();
看看Spring如何继续初始化Spring的环境
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this();
register(annotatedClasses)
refresh();
}
跟进refresh()
, 源码如下: 主要做了如下几件工作
- 刷新的预准备
- 比如: 设置时间的锚点,加载上下文环境变量
- 获取BeanFactory
- 执行所有的
BeanFactoryPostProcessor
- 执行所有的
BeanPostProcessor
- ...
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
//准备刷新
prepareRefresh();
//获取BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备BeanFactory
prepareBeanFactory(beanFactory);
try {
// 方法中没有任何实现的逻辑
postProcessBeanFactory(beanFactory);
// invoke BeanFactoryPostprocessor, 执行bean工厂的后置处理器
//如果我们没有手动往Spring中注入bean工厂的后置处理器,那么此时仅有一个,也是beanFactoryMap中的第一个RootBeanDefinition-> ConfigurationClassPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 注册 bean的后置处理器, 这些处理器可以在bean的构造方法执行之后再执行init()方法前后执行指定的逻辑
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
}
}
刷新的准备工作
这个方法没啥可看的重要逻辑,记录了下开始的时间,然后为Spring的上下文加载可用的环境变量
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// 这个是protected类型的方法,目前还没有任何实现
initPropertySources();
// 校验所有需要的properties是否都被解析过了
// getEnvironment() 得到系统环境, 后续的@Profile使用
getEnvironment().validateRequiredProperties();
this.earlyApplicationEvents = new LinkedHashSet<>();
}
获取BeanFactory
获取出BeanFactory
,接下来的工作重点是去扫描出程序员提供的类,然后将它们放进BeanFactoryMap
中,在此过程中穿插执行BeanFactoryPostProcessor
和BeanPostPorcessor
, 不难看出后续工作的进展都离不开这个BeanFactoryMap
,这个map在哪里呢? 就在我们的beanFactory
中,因此在刷新的最开始,获取出bean工厂
当前类是AbstractApplicationContext
,上图是它的继承类图,通过上图可以看到,它是入口AnnotationConfigApplicationContext
和GenericApplicationContext
的父类,而Spring的BeanFactory
是在GenericApplicationContext
中实例化的,故, 获取beanFactory
的逻辑肯定在当前方法中被设计成抽象的方法,而由自己具体实现,源码如下:
@Override
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
准备beanFactory
上面的逻辑是获取出BeanFactory
, 那什么是准备BeanFactory
呢? 看它的注解解释是: 为BeanFactory
配置上它应该具有的所有特征, 那BeanFactory应该有什么特征呢? 类加载器 , bean表达式的解析器 , property与对象的转换器 , bean的后置处理器 , 添加禁止用户注入的bean的信息 , 注入bean的替换 , 添加默认的和环境相关的bean
源码如下:它的解析我们写在下面
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 添加类加载器
beanFactory.setBeanClassLoader(getClassLoader());
// 设置bean标签的解析器, 一般我们使用spel标签比较多,但是Spring也有自己的Bean标签
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
// </property ref="XXX"> 解析转换xxx 替换成对象
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 添加bean的后置处理器,很显然这里添加的是Spring自己的后置处理器
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 当用户企图注入下面类型的对象时, 会被Spring忽略
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
//用户穿进来的是 BeanFactory.class , 那Spring会将她替换成beanFactory
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Register early post-processor for detecting inner beans as ApplicationListeners.
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// 意思是如果自定义的Bean中没有名为"systemProperties"和"systemEnvironment"的Bean,
// 则注册两个Bena,Key为"systemProperties"和"systemEnvironment",Value为Map,
// 这两个Bean就是一些系统配置和系统环境信息
// 注册默认的和环境相关的 bean Sping会检测,我们自己注册进来的Bean中有没有下面的名字叫下面三个串的对象, 没有的话就帮我们注入进来
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { // environment_bean_name
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {// system_properties_bean_name
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {// system_environment_bean_name
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
如上代码的作用就是为BeanFactory
初始化了Spring规定的几个必须的配置属性,其中比较值得注意的地方就是它添加的BeanPostProcessor
, 虽然这是Spring原生的bean的后置处理器,但是也是第一次出现,很有意义,配置expressContext等工作, 这个后置处理器会在Bean的构造的构造过程中,动态的拦截插手
此外,添加了忽略注入的对象,当程序员向注入Spring启动时,依赖的原生对象时,会被忽略注入,企图注入BeanFactory,资源解析器,事件发布器,应用上下文时,被Spring使用原生的对象替换掉
执行所有的BeanFactory的后置处理器
执行BeanFactory的后置处理器,具体是哪些呢? 其实是两部分,一部分是用户自己添加的,另一部分是Spring在启动过程中自己添加进去的
先说用户自己添加的情况,不知道大家有没有发现,源码读到这里其实还没看到Spring进行包扫描,既然没有进行包扫描那程序员通过@Compoennt
注解添加进去的 bean工厂的后置处理器 就还没有被Spring所识别到,没错,这里能被识别到的 BeanFactoryPostProcessor
是程序员通过context.addBeanFactoryPostProcessor(new MyBeanFactoryPostProcessor());
添加进来的
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
}
继续跟进invokeBeanFactoryPostProcessors()
方法,源码如下,这个方法在执行BeanFactoryPostProcessor
不得不说他真的很重要,很长
它的主要逻辑是: 开始是一个if
分支判断beanFactory
的合法性,上篇博文中我们看到了,所谓的beanFactory其实本身也实现了注册器接口,有注册bean的功能, 于是他将BeanFactory
强转成了注册器类型
紧接着Spring定义了两个新的List, 一个叫regularPostProcessors
一个叫registryProcessors
, 前者用来存放程序员自己添加进来的BeanFactoryPostProcessor
, 后者用来存放程序员自己添加进来的BeanDefinitionRegistryPostProcessor
, 为什么使用两个集合呢? 参见下图:
通过上面的图可以看到,BeanFactoryPostProcessor
是顶级的接口,BeanDefinitionRegistryPostProcessor
是继承了顶级接口然后自己做出了拓展, 一般程序员通过BeanFactoryPostProcessor
在bean的构造方法之前进行插手的话,最常用的就是选择直接自己实现BeanFactoryPostProcessor
,虽然实现BeanDefinitionRegistryPostProcessor
也行
BeanDefinitionRegistryPostProcessor
对BeanFactoryPostProcessor
做出来拓展, Spring需要保证拓展的方法被执行到,重写的父类的方法也要被执行到,因此选择使用两个集合,循环所有的bean工厂的后置处理器,按照不同的分类分别对待
分好类之后,又创建了一个list叫currentRegistryProcessors
这个List中存放的是 Spring自己的提供的BeanFactoryPostProcessor
的实现, 其实这个实现在前面提到过好多次了. 他就是ConfigurationClassPostProcessor
现在一共是三个集合,其中两个集合中的存放的对象是一样的,于是Spring将其实两个存放BeanDefinitionRegistryPostProcessor
的集合进行了合并
接下来就是真正的开始执行的工作
- 执行
BeanDefinitionRegistryPostProcessor
- 执行
BeanFactoryPostProcessor
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
// Invoke BeanDefinitionRegistryPostProcessors first, if any.
Set<String> processedBeans = new HashSet<>();
// 通过看BanFactory的继承体系,能看到它实现了 BeanDefinitionRegistry接口
if (beanFactory instanceof BeanDefinitionRegistry) {
// 将工厂强转成 注册器
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
// 存放程序员添加进来的 BeanFactoryPostProcessor
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
// 存放程序员添加进来的 BeanDefinitionRegistryPostProcessor
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
System.out.println(beanFactoryPostProcessors.size());
// 自定义的beanFactoryPostProcessors
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(BeanDefinitionRegistryPostProcessor) postProcessor;
registryProcessor.postProcessBeanDefinitionRegistry(registry);
registryProcessors.add(registryProcessor);
}
else {//BeanDefinitionRegistryPostProcessor BeanfactoryPostProcessor
// 将自定义的BeanFactoryPostPorcessor 添加到了 上面的 ArrayList中regularPostProcessors
regularPostProcessors.add(postProcessor);
}
}
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
boolean reiterate = true;
while (reiterate) {
reiterate = false;
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
if (!processedBeans.contains(ppName)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
reiterate = true;
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
currentRegistryProcessors.clear();
}
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
...
}
接下来与其说 看一下它如何执行BeanDefinitionRegistryPostProcessor
, 到不如说 看一下如何执行ConfigrationClassPostProcessor
对BeanFactoryPostProcessor
的拓展方法
postProcessor.postProcessBeanDefinitionRegistry(registry);
继续跟进,经过两个没有啥重要逻辑的方法之后,进入到下面的逻辑中, 有来了一个高潮,在这个方法中完成了包扫描工作
一开始获取出beanFactoryMap
中的全部的BeanDefinitionName
, 这时一共有几个? 其实是7个, 其中6个是在创建AnnotatedBeanDefinitionReader
时添加进去的6个, 另外的哪一个就是在前面的register()
方法中,注册的我们的主配置类MainConfig
紧接着是一个循环判断语句,循环这七个BeanDefinition
, 目的有两个,第一个把我们自己的MainConfig
配置类找出来放到下面的configCandidates
集合中,因为这是个配置类啊,上面会有@ComponentScan(value="XXX")
通过这个注解提供的包信息,Spring就能进一步进行包扫描,找到用户提供的所有的类信息,将它们加载进容器中, 第二个判断一下我们的MainConfig
类上有没有添加@Configuration
如果存在这个注解标记它为full,Spring就认为我们的当前的运行的上下文环境是全注解环境,并且会为MainConfig
生成一个cglib代理对象,进一步保证了Spring的单例特征,如果没有这个注解,但是存在@Component @ComponentScan @Import @ImportResource
Spring标记它为lite.认为当前的上下文环境为非全注解模式
怎么理解这个全注解与非全注解呢? 字面意思也是,全注解就是不存在配置文件, 不存在配置文件的话,程序员不可能不提供@ComponentScan
让Spring去扫描完成Bean的注入,同时程序员也会提供一个@Configuration
明确的标识这是一个配置类, 那非全注解呢, 就是可能存在注解和XML共存的现象, Spring这时也会同时支持注解+xml的读取
接着又是排序,创建名称生成器
紧接着创建了一个ConfigurationClassParser
配置类的解析器,这个解析器,见名知意,用来解析配置类, 现在谁是配置类呢? 其实就是在上面的循环中唯一被添加进list的,我们提供的MainConfig
, 因为我在他身上添加了@Configuration
注解
下面的主要逻辑是解析配置类,我把解释写在如下代码的下面
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
// 定义一个List 存放项目中添加了 @Compennt注解的类
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
// 获取容器中注册的所有bd名字
// 一共 7个 , 6个rootBeanDefinition 1个我们自己的MainConfig
// 获取出一开始我们Spring自己添加的6个Processor, 和我们添加的MainConfig
String[] candidateNames = registry.getBeanDefinitionNames();
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
//
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) ||
ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
// 他是怎么判断出来的呢? 在上面, 如果判断得出当前的类添加了@Configration , 就给他标记 full, 在上面的if分支语句中,添加了full的类,不会添加进 configCandidates 中,故为空
if (configCandidates.isEmpty()) {
return;
}
// Sort by previously determined @Order value, if applicable
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
// Detect any custom bean name generation strategy supplied through the enclosing application context
SingletonBeanRegistry sbr = null;
// 现在我们使用的BeanDefinitionRegistry是其实是Spring的Bean工厂(DefaultListableBeanFactory) 他是SingletonBeanRegistry的子类的话
if (registry instanceof SingletonBeanRegistry) {
// 将registry强转为SingletonBeanRegistry
sbr = (SingletonBeanRegistry) registry;
if (!this.localBeanNameGeneratorSet) {
// 是否有自定义的
BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(CONFIGURATION_BEAN_NAME_GENERATOR);
//SingletonBeanRegistry中有id为 org.springframework.context.annotation.internalConfigurationBeanNameGenerator
// 如果有则利用他的,否则是spring默认的
if (generator != null) {
this.componentScanBeanNameGenerator = generator;
this.importBeanNameGenerator = generator;
}
}
}
if (this.environment == null) {
this.environment = new StandardEnvironment();
}
// 这是个配置类的解析器 会解析每一个添加了 @Configuration 的类
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
do {
// 仅仅处理添加了@Configuration注解的类, 进行包扫描,跟进去
parser.parse(candidates);
// 运行到这里完成了扫描,BeanFactory中的BeanDefinitionMap中就多了我们字节添加进去的bean信息
parser.validate();
//map.keyset
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
...
跟进这个 parser.parse(candidates);
,这里就来到了又一波高潮,准备开始包扫描了
不怕麻烦,再提一下,当前的这个对象就是我们的MianConfig
,它是被AnnotatedBeanDefinitionReader
读取到的,所以它一定是AnnotatedBeanDefinition
, 所以一定会进入到第一个if分支中
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<>();
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
if (bd instanceof AnnotatedBeanDefinition) {
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
继续跟进,同样是经过了几个没有重要逻辑的方法之后,进入到下面的方法中,看他是如何下面这个重要的方法中
这个方法主要做了两件大事:
- 处理扫描添加有
@Component
注解的普通类,并将它们直接添加到BeanFactoryMap
中 - 扫描处理添加有
@Import
注解
看他首先取出所有的@CompoenntScan
注解,循环遍历注解,每次循环都使用this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
进行真正的包扫描
跟进这个方法中,可以看到它一开始就自己重新new 了一个包扫描器,然后解析当前循环的@ComponentScan
注解上的其他如excludeFilters,includeFilters
等属性,最后开始真正的进行包扫描, 在这个扫描的过程中,会将命中符合条件的普通类(如被@Component
标识),进行如下处理
- 设置scope信息
- 生成BeanName
- 给扫描出来的这些添加上默认的属性信息比如默认全是
Lazy
- 进一步,处理这些类上的注解信息,比如
@Lazy , @Primary , @DependsOn , @Role , @Description
,用这些信息覆盖默认的信息 - 将扫描出来的普通类直接添加到BeanFactoryMap中
完成了上面的普通类的扫描工作之后,下一个高潮就来了,处理@Import()的三中情况,它的解析我写在如下代码的下面
protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
throws IOException {
// Recursively process any member (nested) classes first
// 递归地首先处理任何成员(嵌套)类
processMemberClasses(configClass, sourceClass);
// Process any @PropertySource annotations
for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
if (this.environment instanceof ConfigurableEnvironment) {
processPropertySource(propertySource);
}
else {
logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
"]. Reason: Environment must implement ConfigurableEnvironment");
}
}
// 处理所有的@ComponentScan注解, 也就是读取到了我们在MainConfig中使用@ConponentScans 中添加的元信息, 如value=com.changwu
// basePackages lazyInit userDefualtFileter ,,, includeFileters excludeFilters scopeResolver nameGenerate ,,,
// Process any @ComponentScan annotations
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
if (!componentScans.isEmpty() &&
!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
// 为什么要循环,以为 @ComponentScans(value={1,2,3}) value是一个数组
for (AnnotationAttributes componentScan : componentScans) {
// The config class is annotated with @ComponentScan -> perform the scan immediately
// 扫描com.changwu下面的普通类, 也就是添加了@Component注解的类, 然后将扫描出来的bean放到map中
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
// Check the set of scanned definitions for any further config classes and parse recursively if needed
//检查扫描出来的类当中是否还有configuration
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
if (bdCand == null) {
bdCand = holder.getBeanDefinition();
}
//检查 看看被扫描的普通类有没有添加 配置相关的注解
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
}
processImports(configClass, sourceClass, getImports(sourceClass), true);
// Process any @ImportResource annotations
AnnotationAttributes importResource =
...
跟进上面的 processImports(configClass, sourceClass, getImports(sourceClass), true);
方法,看他如何处理@Import
注解,通过下面的代码不难看出@Import
注解存在三种情况,分别是
- ImportSelector
- ImportBeanDefinitionRegistrar
- 普通类
第一种情况处理ImportSelector
, 这个ImportSelector
是很好用的组件,首先第一点: 我们可以通过自动ImportSelector
完成类的批量注入,但是吧这个功能感觉就像是鸡肋,弃之可惜,食之无味, 其实他还有一个妙用!配合jdk的动态代理我们可以实现类似AOP的切面,针对某一个对象进行动态的代理, 举个例子: 自定义一个类,实现BeanPostProcessor
接口,然后重写它的public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { ... }
然后根据用户名进行判断,当找我们指定的用户时,我们可以使用JDK的动态代理完成将这个对象转换成代理对象,进而实现切面的增强
看一下它的处理,它判断出@Import
中含有ImportSelector.class
时,就通过反射将这个对象创建出来代理对象,狸猫换太子,把代理对象交给Spring,得到ImportSelector
的对象,具体反射出来的对象的实例就是程序员自定义的那个ImportSelector
,得到这个对象之后,然后调用它的selectImports()
方法,就返回了程序员指定的想批量导入DaoIOC中的对象的全类名, 下一步就是将这些类注入到IOC中,Spring的做法是递归调用, 因为上面说了,当前方法可以实现的三种Bean的注入,一般来说,通过 ImportSelecor
导入的类就是普通类了, 会进入下面代码中的最后一个else语句块
第二种情况,处理ImportBeanDefinitionRegistrar
,Spring的做法是,将它添加进一个map中
this.importBeanDefinitionRegistrars.put(registrar, importingClassMetadata);
第三种情况,同样和第一种情况是一样的,也是先将信息放到map中
this.configurationClasses.put(configClass, configClass);
源码如下:
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, boolean checkForCircularImports) {
// 如果没有添加了@Implot注解的类,直接退出去
if (importCandidates.isEmpty()) {
return;
}
if (checkForCircularImports && isChainedImportOnStack(configClass)) {
this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
}
else {
this.importStack.push(configClass);
try {
for (SourceClass candidate : importCandidates) {
// 情况1: 处理 @ImportSelector 注解
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
// 被循环获取出现在Spring自己的以及扫描出来的全部的对象的Class描述
Class<?> candidateClass = candidate.loadClass();
// 只要这个对象的@Import(value= ImportSelector.clas)就被命中
// 反射实现一个对象,反射创建的这个对象就是我们的手动添加的 继承 ImportSelector 的那个对象
ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
ParserStrategyUtils.invokeAwareMethods(
selector, this.environment, this.resourceLoader, this.registry);
if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
this.deferredImportSelectors.add(
new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
} else {
// 回调反射出来的这个对象啊的 SelectImports() 方法,就能动态的获取出我们手动添加进去的,准备批量注入的 对象的 ClassName 数组
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
// 将importClassNames添加进一个list -- annotatedClasses中,然后返回出来
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
// 递归调用, processImports()方法,显然,再次递归的话,传递进去的importSourceClasses就是当前的类, 如果当前类是普通类,递归时就不再来到这里了, 而是进入下面的else代码块
processImports(configClass, currentSourceClass, importSourceClasses, false);
}
} // 情况2: 处理@ImportBeanDefinitionRegistrar
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
ImportBeanDefinitionRegistrar registrar =
BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
ParserStrategyUtils.invokeAwareMethods(
registrar, this.environment, this.resourceLoader, this.registry);
// 没有和上面一样进行回调,而是放入到一个list中
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
// 情况3: 处理普通类
// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
// process it as an @Configuration class
// 否则,加入到importStack后调用 processConfigurationClass 进行处理
//processConfigurationClass() 方法就在下面, 里面主要就是把类放到configurationClasses
//configurationClasses是一个集合,会在后面拿出来解析成bd继而注册
//可以看到普通类在扫描出来的时候就被注册了
//如果是importSelector,会先放到configurationClasses后面进行出来注册
this.importStack.registerImport(
currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
processConfigurationClass(candidate.asConfigClass(configClass));
}
}
}
当处理完成了三种@Import
类型的导入方式之后,我们继续往下看,三种方式都是忙着把读取读来的信息往map中放,那么在哪里进行处理的呢? 思考一下,接下来是不是得将读取到的信息注册进IOC中? 没错,我们退会到ConfigurationClassPostProcessor
中的this.reader.loadBeanDefinitions(configClasses);
方法中
同样经过几个没有重要逻辑的方法之后,我们来到了ConfigurationClassBeanDefinitionReader
中,着重它的loadBeanDefinitionsForConfigurationClass()
方法, 源码我贴在下面:
看看他做了什么, 一目了然,很清晰的思路,很牛逼很牛逼!!!
如果Spring发现,当前的类是被导入进来的,他按照Bean导入进来的方式进行注册Bean,如果进给看一下,就能看熟悉的一幕,Spring使用Register
进行Bean的注册
如果Spring发现它有BeanMethod,也就是发现这个对象存在方法,换句话说发现我们的对象存在方法,就会进一步解析我们的方法,怎么解析方法呢? 按照对象的方法和类的方法分别解析,这也是为什么,当我们在配置类的静态方法中使用@Bean进行注入对象,即使已经为MainConfig生成了代理,依然会出现重复注入对象的情况,但是BeanName不一样哦,如果是静态方法+@Bean, BeanName是当前的方法名
接下来的逻辑是 解析XML与处理Registrar
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) {
// 如果一个类是被 Import 进来的, 会在Spring进行标记,然后再这里完成注册
// @Import(aaa.class) 那这个aaa就是被Import的,在这里完成注册
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
loadBeanDefinitionsForBeanMethod(beanMethod);
}
// xml
loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
// 处理注册Registrar 的逻辑
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
代码读到这里其实已经深入很多层了,重要的逻辑也都过了一下,现在的工作就是层层的往回出栈,回到开始的PostProcessorRegistationDelegate
中的invokeBeanFactoryPostProcessors()
方法
上面的大部分篇幅都是当前方法中的 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
方法层层递归进去的,现在我们从它开始往后看
刚开始不是说,一共是创建三个list吗?然后又把其中的两个进行了合并了, 那么接下来的工作就是去执行这两个list中剩下的没执行的逻辑, 没执行的就是,Spring自己提供的和程序员添加的BeanFactoryPostProcessor
的实现,没错就是执行重写的BeanFactoryPostProcessor()
的postProcessBeanFactory()
方法
// registryProcessors 其实就是唯一的 ConfigurationClassPostProcessor
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
// 自定义BeanFactoryPostProcessor 的 postProcessorBeanFactory()方法
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
大家看,上面的两个方法是一样,只不过是传递进去的参数不一样而已,其实吧,高潮来了,如果大家还记得的话,应该猜到了现在的入参位置上的参数, 没错就是 ConfigurationClassPostProcessor
这个类, 它太牛逼了! 同时实现了BeanDefinitionRegistryPostProcessor
和BeanFactoryPostProcessor
的抽象方法, 下面就去具体看一下它的实现,准备好了吗? 来高潮了哦
源码如下: 它的解析我写在下面
@Override
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);
}
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
enhanceConfigurationClasses(beanFactory);
这是在干什么? 跟大家说,这太牛了!!!为什么说它牛? 不买关子,它在这里开启了JDK的动态代理
在这个方法中有一段判断逻辑,如下: 这是很赞的一段代码,感觉到了心跳的加速! 它判断当前的这个BeanDefinition
是不是full类型的, 关于这个Full的解释,其实我们上面的描述中有说过,就是说,如果我们的MainConfig
添加了@Configuration
注解,它就被会标记为FUll, 被标记为full的话,就会在下面的代码中产生cglib的动态代理,也就是说,我们获取到的存入容器的MainConfig
可以不是普通的原始对象, 而是被Cglib增强后的对象, 这有什么用呢? 用处可大了! 我们通常会在配置类中添加@Bean注解,注入对象,但是如果被添加了@Bean注解的方法彼此之间相互调用的户,就会出现重复注入的现象,Spring通过下面的判断,进行代理,不再给用户原始的Mainconfig
,这样就实现对方法调用的控制,进而保证了百分百单例的情况
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
// 判断isFull, 看看是不是添加了@Configuration的全注解的类
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
}
else if (logger.isWarnEnabled() && beanFactory.containsSingleton(beanName)) {
logger.warn("Cannot enhance @Configuration bean definition '" + beanName +
"' since its singleton instance has been created too early. The typical cause " +
"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
"return type: Consider declaring such methods as 'static'.");
}
// 如果是的话,放到这个linkedHashMap中
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
接着往下看代码就可以看到Spring底层使用原生cglib进行代理的逻辑了,
private Enhancer newEnhancer(Class<?> configSuperClass, @Nullable ClassLoader classLoader) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(configSuperClass);
enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
enhancer.setUseFactory(false);
enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
enhancer.setCallbackFilter(CALLBACK_FILTER);
enhancer.setCallbackTypes(CALLBACK_FILTER.getCallbackTypes());
return enhancer;
}
这个过程中有几个需要注意的地方,一般我们自己实现Cglib时, 都只是设置一个setSuperclass(XXX)
然后对这个XXX进行增强,但是Spring没这么简单,它还enhancer.setInterfaces(new Class<?>[] {EnhancedConfiguration.class});
想想,为什么还要这个接口呢?看下面的图
通过上面的图可以看到,这个接口实现了beanFactoryAware
,而这个beanFactory
中存在setBeanFactory(BeanFactory bf)
怎么样? 有思路没?
整理一下思路,就是说,Spring的目的就是将程序员传递进来的MainConfig
进行动态代理,为啥要代理呢? 因为有的程序员会故意搞破坏,会使用被@Bean
标注的方法之间相互调用,导致Bean的多次注入,于是Spring想通过代理,返回给用户一个代理对象,然后添加动态的判断, 如果容器中已经存在bean了,就从容器中获取,不再重复注入,没有的话就注入进去一个
这就引出了为什么,代理对象需要一个BeanFactory
,因为BeanDefinition
都在BeanFactory中,这也是为什么上面需要setInterface()
接着enhancer.setStrategy(new BeanFactoryAwareGeneratorStrategy(classLoader));
设置一个生成策略, 因为我们生曾的代理类需要一个BeanFactory类型的变量啊,没有这个引用,如何接受前面set的BeanFactory???
再往后的亮点就是enhancer.setCallbackFilter(CALLBACK_FILTER);
设置回调的拦截器,看看有哪些拦截器呢? 代码如下:
private static final Callback[] CALLBACKS = new Callback[] {
// 第一个实现, 增强方法, 主要控制bean的作用域换句话说就是让每一次调用方法不再去new, 跟进去看看
new BeanMethodInterceptor(), // 他是当前类的内部类
//设置一个beanFactory
new BeanFactoryAwareMethodInterceptor(),
NoOp.INSTANCE
};
我们跟进去BeanMethodInterceptor
,这个类也很精彩,玩过cglib的人都知道需要一个inteceptor,而我们正在看的这个接口就实现了methodInterceptor
,重不重要,你懂的...
直接看它的intercept()
方法, 细细品味这个方法,很有味道哦!!!, 它的解析我写在这个方法的下面
public Object intercept(Object enhancedConfigInstance, Method beanMethod, Object[] beanMethodArgs,
MethodProxy cglibMethodProxy) throws Throwable {
// enhancedConfigInstance 是代理对象
// 通过代理对象enhancedConfigInstance中cglib生成的成员变量$$beanFactory获得beanFactory。
ConfigurableBeanFactory beanFactory = getBeanFactory(enhancedConfigInstance);
String beanName = BeanAnnotationHelper.determineBeanNameFor(beanMethod);
// Determine whether this bean is a scoped-proxy
Scope scope = AnnotatedElementUtils.findMergedAnnotation(beanMethod, Scope.class);
if (scope != null && scope.proxyMode() != ScopedProxyMode.NO) {
String scopedBeanName = ScopedProxyCreator.getTargetBeanName(beanName);
if (beanFactory.isCurrentlyInCreation(scopedBeanName)) {
beanName = scopedBeanName;
}
}
if (factoryContainsBean(beanFactory, BeanFactory.FACTORY_BEAN_PREFIX + beanName) &&
factoryContainsBean(beanFactory, beanName)) {
Object factoryBean = beanFactory.getBean(BeanFactory.FACTORY_BEAN_PREFIX + beanName);
if (factoryBean instanceof ScopedProxyFactoryBean) {
// Scoped proxy factory beans are a special case and should not be further proxied
}
else {
return enhanceFactoryBean(factoryBean, beanMethod.getReturnType(), beanFactory, beanName);
}
}
if (isCurrentlyInvokedFactoryMethod(beanMethod)) {
// The factory is calling the bean method in order to instantiate and register the bean
// (i.e. via a getBean() call) -> invoke the super implementation of the method to actually
// create the bean instance.
if (logger.isWarnEnabled() &&
BeanFactoryPostProcessor.class.isAssignableFrom(beanMethod.getReturnType())) {
logger.warn(String.format("@Bean method %s.%s is non-static and returns an object " +
"assignable to Spring's BeanFactoryPostProcessor interface. This will " +
"result in a failure to process annotations such as @Autowired, " +
"@Resource and @PostConstruct within the method's declaring " +
"@Configuration class. Add the 'static' modifier to this method to avoid " +
"these container lifecycle issues; see @Bean javadoc for complete details.",
beanMethod.getDeclaringClass().getSimpleName(), beanMethod.getName()));
}
// 满足条件 调用父类的构造方法new 对象
return cglibMethodProxy.invokeSuper(enhancedConfigInstance, beanMethodArgs);
}
return resolveBeanReference(beanMethod, beanMethodArgs, beanFactory, beanName);
}
首先,它从代理对象中获取出beanFactory
然后他处理 FactoryBean
的情况,这个FactoryBean
太牛了,因为当程序员把一个FactoryBean
注入到IOC时,附带的还会把另一个对象驻入进IOC, 它是如何进行区分判断的呢? Spring会使用一个BeanFactory.FACTORY_BEAN_PREFIX == &
这个前缀去匹配, 比如userDao3()中调用了userDao4(), 他就是用&userDao4当成key去beanFactory中获取,如果获取获取出对象了,说明这是个FactoryBean
需要对获取出来的这个对象进一步生成代理
接下来判断,是new 呢? 还是从Factory中获取呢?
Spring的判断依据是根据方法名,判断调用方法和正在执行的方法是同一个方法,根据什么呢? 只要名字相同, 结论就是直接new
举个例子:
userDao3(){}
// 它的调用方法和正在执行的方法是同一个方法,怎么相同呢? 名字相同, 结论就是直接new
userDao4(){
userDao3()
}
userDao4()是调用方法, userDao3()执行方法 userDao4 和 userDao3 名字不一样, 所以选择getBean()
第二个例子:
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("intercept.............");
methodProxy.invokeSuper(o,objects);
return null;
}
比如我们仅仅执行代理方法A, 这个A方法 就时上面的method 也是methodProxy, 但是如果我们在代理方法A中执行B方法, 这时 A == method != methodProxy == B
代码看到这里,其实一开始的refresh()
中的invokeBeanFactoryPostProcessors(beanFactory);
方法就看完了, 着呢么样刺激不?
有错误的话欢迎批评指出,有过对您有帮助,欢迎点赞支持