基于注解的启动流程

使用xml进行spring的配置终究已经不是主流,在springboot流行的当今,基于注解的配置才是主流.既然已经对基于xml文件的容器进行了一定的了解,那么也该对基于注解的启动流程进行学习了

注解的前置工作

基于注解的配置,是不是有点springboot的味道了

@ComponentScan
public class Start {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Start.class);
        System.out.println("============"+context.getBean(People.class)+"=============");
    }
}

People 类

package com.zk.sixDay;

import org.springframework.stereotype.Service;

/**
 * @author zhaokun
 * @since 2021/1/14 15:40
 */
@Service
public class People {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "People{" +
                "name='" + name + '\'' +
                '}';
    }
}

结果
在这里插入图片描述

注解的源码分析

AnnotationConfigApplicationContext的AnnotationConfigApplicationContext(Class<?>… componentClasses)

	public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
		//这里实例化了reader和scanner
		this();
		//这里将传入的class对象注册到BeanDenifition中
		register(componentClasses);
		//和xml一样,都会进入到refresh方法
		refresh();
	}

AnnotationConfigApplicationContext的AnnotationConfigApplicationContext()

	public AnnotationConfigApplicationContext() {
		//实例化reader,在这个过程中,完成了各种内置postprocessor的注册工作
		this.reader = new AnnotatedBeanDefinitionReader(this);
		//实例化scanner
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

AnnotatedBeanDefinitionReader()的构造方法

	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		Assert.notNull(environment, "Environment must not be null");
		this.registry = registry;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		//在此注册了一系列的BeanFactoryPostProcessor的实现类,其中包含一个很重要的类
		//ConfigurationClassPostProcessor.class
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

至于ClassPathBeanDefinitionScanner类的实例化,在此不再赘述,因为在之前的博客<component-scan标签解析>中有对改类实例化的分析.
此时便会调用refresh()方法.

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			prepareRefresh();
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
			prepareBeanFactory(beanFactory);
			try {
				postProcessBeanFactory(beanFactory);
				invokeBeanFactoryPostProcessors(beanFactory);
				registerBeanPostProcessors(beanFactory);
				initMessageSource();
				initApplicationEventMulticaster();
				onRefresh();
				registerListeners();
				finishBeanFactoryInitialization(beanFactory);
				finishRefresh();
				....
	}

xml文件的解析是在执行 obtainFreshBeanFactory() 时完成的.而在基于注解的启动时,该方法不能够型增任何其他的BeanDenition.此时将会执行到 invokeBeanFactoryPostProcessors(beanFactory) 中,而invokeBeanFactoryPostProcessors方法已经在之前的博客中介绍了它的作用,简单说下这里面就是对实现BeanFactoryPostProcessor接口的方法的优先执行,在此debug看下有哪些BeanDenifitions
在这里插入图片描述
在这时并没有People类被注册到beanDefinitionMap中
在这里插入图片描述
继续debug后,发现people类被注册进去了.因此才有了后面取得了People类,那么这里的People是怎么注册进去的呢,scanner并没有扫描,这时就涉及到一个很重要的类了 ConfigurationClassPostProcessor.class

注解的核心处理

ConfigurationClassPostProcessor是极为重要的一个类,概述它的作用就是对被扫描的类上面的注解进行解析,万一解析了其他类也符合条件变成BeanDenition,对于新的BeanDenition的类也会去解析它的注解,以此反复递归下去.最后把有关联的符合条件的类全部加载到容器中
ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry)

	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
		...
		//核心方法
		processConfigBeanDefinitions(registry);
	}

然后看下ConfigurationClassPostProcessor的processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法好长啊0.0!

	public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames();
		//获取容器中的BeanDefinition,对他们进行遍历处理
		for (String beanName : candidateNames) {
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			//判断下该类有没有被ConfigurationClassPostProcessor类处理过
			if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
				if (logger.isDebugEnabled()) {
					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
				}
			}
			//这里去判断BeanDenition中是否含有@Configuration注解或者@Bean注解或者@Component,@ComponentScan
			//@Import,@ImportResource这些注解,要是包含,就加入到候选处理的集合中
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		// 要是没有需要处理的类,则直接返回出去
		if (configCandidates.isEmpty()) {
			return;
		}

		// 对候选处理的类进行排序
		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;
		if (registry instanceof SingletonBeanRegistry) {
			sbr = (SingletonBeanRegistry) registry;
			if (!this.localBeanNameGeneratorSet) {
				BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
						AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
				if (generator != null) {
					this.componentScanBeanNameGenerator = generator;
					this.importBeanNameGenerator = generator;
				}
			}
		}

		if (this.environment == null) {
			this.environment = new StandardEnvironment();
		}

		// 委托模式,创建一个委托对象
		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注解或者@Bean注解或者@Component,@ComponentScan
			//@Import,@ImportResource这些注解进行处理的
			parser.parse(candidates);
			parser.validate();

			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();
			if (registry.getBeanDefinitionCount() > candidateNames.length) {
				String[] newCandidateNames = registry.getBeanDefinitionNames();
				Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
				Set<String> alreadyParsedClasses = new HashSet<>();
				for (ConfigurationClass configurationClass : alreadyParsed) {
					alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
				}
				for (String candidateName : newCandidateNames) {
					if (!oldCandidateNames.contains(candidateName)) {
						BeanDefinition bd = registry.getBeanDefinition(candidateName);
						if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
								!alreadyParsedClasses.contains(bd.getBeanClassName())) {
							candidates.add(new BeanDefinitionHolder(bd, candidateName));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
		//循环结束的条件
		while (!candidates.isEmpty());

		// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
		if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
			sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
		}

		if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
			// Clear cache in externally provided MetadataReaderFactory; this is a no-op
			// for a shared cache since it'll be cleared by the ApplicationContext.
			((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
		}
	}

因为ConfigurationClassPostProcessor类太复杂,本博客只是大体的说明下该类的功能,对于其中方法的详细解析,会另开一篇博客来分析的.其中的循环递归也会在那篇博客中分析到

基于注解的解析,首先在实例化时就将ConfigurationClassPostProcessor这个类注册到了容器中,而这个类又是后置处理器,会在实例化前先执行方法,在这个过程中会去解析已经注册的类的注解,进而去执行注解的功能,其中包含的注解总结如下:
@Configuration : 会被扫描到,并且默认会生成代理
@Bean : 会被扫描到生成工厂方法的bean对象
@Component : 会被扫描到
@ComponentScan : 会扫描包下的带有@Component的类和子类并加入到BeanDefinitions里,在对新扫描进入的类进行递归
@Import : 引入类
@ImportResource : 引入xml文件(或者其他文件)
@PropertyResource:引入properties文件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值