zoukankan      html  css  js  c++  java
  • 深入理解 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);方法就看完了, 着呢么样刺激不?

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

  • 相关阅读:
    Spring-web初始化流程简图
    记一次升级Tomcat
    Spring-Task思维导图
    2019的第一个工作日
    RocketMQ专题2:三种常用生产消费方式(顺序、广播、定时)以及顺序消费源码探究
    RocketMQ专题1:入门
    博客搬家到云栖社区
    ActiveMQ专题2: 持久化
    ActiveMQ专题1: 入门实例
    linux下怎么卸载自带的JDK和安装想要的JDK
  • 原文地址:https://www.cnblogs.com/ZhuChangwu/p/11681101.html
Copyright © 2011-2022 走看看