深入理解 Spring BeanFactoryPostProcessor的回调

程序入口:

接着上一篇博客中看完了在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中,在此过程中穿插执行BeanFactoryPostProcessorBeanPostPorcessor, 不难看出后续工作的进展都离不开这个BeanFactoryMap,这个map在哪里呢? 就在我们的beanFactory中,因此在刷新的最开始,获取出bean工厂

继承类图

当前类是AbstractApplicationContext,上图是它的继承类图,通过上图可以看到,它是入口AnnotationConfigApplicationContextGenericApplicationContext的父类,而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, 为什么使用两个集合呢? 参见下图:

beanPostProcessor继承体系图

通过上面的图可以看到,BeanFactoryPostProcessor是顶级的接口,BeanDefinitionRegistryPostProcessor是继承了顶级接口然后自己做出了拓展, 一般程序员通过BeanFactoryPostProcessor在bean的构造方法之前进行插手的话,最常用的就是选择直接自己实现BeanFactoryPostProcessor,虽然实现BeanDefinitionRegistryPostProcessor也行

BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor做出来拓展, 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, 到不如说 看一下如何执行ConfigrationClassPostProcessorBeanFactoryPostProcessor的拓展方法

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 @ImportResourceSpring标记它为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这个类, 它太牛逼了! 同时实现了BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor的抽象方法, 下面就去具体看一下它的实现,准备好了吗? 来高潮了哦

源码如下: 它的解析我写在下面

@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}); 想想,为什么还要这个接口呢?看下面的图

enheanceConfiguration继承体系图

通过上面的图可以看到,这个接口实现了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);方法就看完了, 着呢么样刺激不?

有错误的话欢迎批评指出,有过对您有帮助,欢迎点赞支持

posted @ 2019-10-15 21:19  赐我白日梦  阅读(2856)  评论(0编辑  收藏  举报