我是靠谱客的博主 忐忑吐司,最近开发中收集的这篇文章主要介绍一、Spring IOC容器启动过程源码学习,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1、配置类启动代码:

@Configuration
@Import(value = {TulingService.class})
@ComponentScan(basePackages = "com.tuling.testspringiocstarter")
public class MainConfig {

    @Bean
    public TulingDataSource tulingDataSource() {
        return new TulingDataSource();
    }
}

public class MainClass {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(MainConfig.class);
        System.out.println(ctx.getBean(TulingDao.class));
    }
}

IOC容器继承图

 需要注意的是,我们在Tomcat等web环境下的容器类为:AnnotationConfigWebApplicationContext,它在spring-web包下

Spring容器里通过BeanDefinition对象来表示Bean,BeanDefinition描述了Bean的配置信息。
BeanDefinitionRegistry接口提供了向容器注册,删除,获取BeanDefinition对象的方法。

简单来说,BeanDefinitionRegistry可以用来管理BeanDefinition,所以理解AnnotationConfigApplicationContext很关键,它是spring加载bean,管理bean的最重要的类。
源码跟踪:

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
		this();
		register(annotatedClasses);
		refresh();
}

一:this(),调用无参构造器 

public AnnotationConfigApplicationContext() {
        // 预先注册一些BeanPostProcessor和BeanFactoryPostProcessor,这些处理器会在接下来的spring初始化流程中被调用
		this.reader = new AnnotatedBeanDefinitionReader(this);
        // 扫描指定目录下的带有@component注解极其派生类,然后将这些类的实例交给BeanDefinitionReqistry
		this.scanner = new ClassPathBeanDefinitionScanner(this);
}

AnnotatedBeanDefinitionReader初始化,构造器如下

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
	this(registry, getOrCreateEnvironment(registry));
}

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;
			
	//ConditionEvaluator完成条件注解的判断,在后面的Spring Boot中有大量的应用
	this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
	//这句会把一些自动注解处理器加入到AnnotationConfigApplicationContext下的BeanFactory的BeanDefinitions中  具体见下面
	AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}

这里将AnnotationConfigApplicationContext注册为管理BeanDefinition的BeanDefinitionRegistry,也就是说,spring中bean的管理完全交给了AnnotationConfigApplicationContext

AnnotationConfigUtils#registerAnnotationConfigProcessors()
我们要用一些注解比如:@Autowired/@Required/@Resource都依赖于各种各样的BeanPostProcessor来解析(AutowiredAnnotation、RequiredAnnotation、CommonAnnotationBeanPostProcessor等等)向这种非常常用的,让调用者自己去申明,显然使用起来就过重了。所以Spring为我们提供了一种极为方便注册这些BeanPostProcessor的方式(若是xml方式,配置<context:annotation- config/>,若是全注解驱动的ApplicationContext,就默认会执行)

public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
	registerAnnotationConfigProcessors(registry, null);
}

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
		BeanDefinitionRegistry registry, @Nullable Object source) {
	
	// 把我们的beanFactory从registry里解析出来
	DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
	if (beanFactory != null) {
		if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
			beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
		}
		// 相当于如果没有这个AutowireCandidateResolver,就给设置一份ContextAnnotationAutowireCandidateResolver
		if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
			beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
		}
	}
	
	//这里初始长度放4  是因为大多数情况下,我们只会注册4个BeanPostProcessor 如下(不多说了)
	// BeanDefinitionHolder解释:持有name和aliases,为注册做准备
	// Spring 4.2之后这个改成6我觉得更准确点
	Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(4);

	if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	if (!registry.containsBeanDefinition(REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(RequiredAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, REQUIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
	// 支持JSR-250的一些注解:@Resource、@PostConstruct、@PreDestroy等
	if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
	}

	// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
	// 若导入了对JPA的支持,那就注册JPA相关注解的处理器
	if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition();
		try {
			def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
					AnnotationConfigUtils.class.getClassLoader()));
		}
		catch (ClassNotFoundException ex) {
			throw new IllegalStateException(
					"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
		}
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
	}


	// 下面两个类,是Spring4.2之后加入进来的,为了更好的使用Spring的事件而提供支持 
	// 支持了@EventListener注解,我们可以通过此注解更方便的监听事件了(Spring4.2之后)
	// 具体这个Processor和ListenerFactory怎么起作用的,且听事件专题分解
	if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
	}
	if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
		RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
		def.setSource(source);
		beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
	}

	return beanDefs;
}
  • ConfigurationClassPostProcessor是一个BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor处理器,BeanDefinitionRegistryPostProcessor的处理方法能处理@Configuration等注解。ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()方法内部处理@Configuration,@Import,@ImportResource和类内部的@Bean。

ConfigurationClassPostProcessor类继承了BeanDefinitionRegistryPostProcessor。BeanDefinitionRegistryPostProcessor类继承了BeanFactoryPostProcessor。
通过BeanDefinitionRegistryPostProcessor可以创建一个特别后置处理器来将BeanDefinition添加到BeanDefinitionRegistry中。它和BeanPostProcessor不同,BeanPostProcessor只是在Bean初始化的时候有个钩子让我们加入一些自定义操作;而BeanDefinitionRegistryPostProcessor可以让我们在BeanDefinition中添加一些自定义操作。在Mybatis与Spring的整合中,就利用到了BeanDefinitionRegistryPostProcessor来对Mapper的BeanDefinition进行了后置的自定义处理。

  • AutowiredAnnotationBeanPostProcessor是用来处理@Autowired注解和@Value注解的
  • RequiredAnnotationBeanPostProcessor这是用来处理@Required注解
  • CommonAnnotationBeanPostProcessor提供对JSR-250规范注解的支持@javax.annotation.Resource、@javax.annotation.PostConstruct和@javax.annotation.PreDestroy等的支持。
  • EventListenerMethodProcessor提供@PersistenceContext的支持。
  • EventListenerMethodProcessor提供@ EventListener 的支持。@ EventListener实在spring4.2之后出现的,可以在一个Bean的方法上使用@EventListener注解来自动注册一个ApplicationListener。

ClassPathBeanDefinitionScanner的初始化:

public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
		Environment environment, @Nullable ResourceLoader resourceLoader) {

	Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
	this.registry = registry;
	
	//useDefaultFilters为true,所以此处一般都会执行
	// 当然我们也可以设置为false,比如@ComponentScan里就可以设置为false,只扫描指定的注解/类等等
	if (useDefaultFilters) {
		registerDefaultFilters();
	}
	// 设置环境
	setEnvironment(environment);
	// 详情如下:  这里resourceLoader传值,还是我们的工厂。否则为null
	setResourceLoader(resourceLoader);
}


protected void registerDefaultFilters() {
	// 这里需要注意,默认情况下都是添加了@Component这个注解的
	//(相当于@Service @Controller @Respository等都会扫描,因为这些注解都属于@Component)  另外@Configuration也属于哦
	this.includeFilters.add(new AnnotationTypeFilter(Component.class));
	ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
	
	//下面两个 是兼容JSR-250的@ManagedBean和330的@Named注解
	try {
		this.includeFilters.add(new AnnotationTypeFilter(
				((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
		logger.debug("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
	} catch (ClassNotFoundException ex) {
		// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
	}
	try {
		this.includeFilters.add(new AnnotationTypeFilter(
				((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
		logger.debug("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
	} catch (ClassNotFoundException ex) {
		// JSR-330 API not available - simply skip.
	}
	
	// 所以,如果你想Spring连你自定义的注解都扫描,自己实现一个AnnotationTypeFilter就可以啦
}

 ClassPathBeanDefinitionScanner继承于ClassPathScanningCandidateComponentProvider,它内部维护有两个final类型的List:这两个对象在执行本类的scanCandidateComponents()方法时就会起作用。

//includeFilters中的就是满足过滤规则的
private final List<TypeFilter> includeFilters = new LinkedList<>();
//excludeFilters则是不满足过滤规则的
private final List<TypeFilter> excludeFilters = new LinkedList<>();

二:register(annotatedClasses)

public void register(Class<?>... annotatedClasses) {
	Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
	this.reader.register(annotatedClasses);
}

public void register(Class<?>... annotatedClasses) {
	for (Class<?> annotatedClass : annotatedClasses) {
		registerBean(annotatedClass);
	}
}

public void registerBean(Class<?> annotatedClass) {
	registerBean(annotatedClass, null, (Class<? extends Annotation>[]) null);
}

public void registerBean(Class<?> annotatedClass, String name, Class<? extends Annotation>... qualifiers) {
    // 先把此实体类型转换为一个BeanDefinition
	AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
    //abd.getMetadata() 元数据包括注解信息、是否内部类、类Class基本信息等等
	// 此处由conditionEvaluator#shouldSkip去过滤,此Class是否是配置类。
	// 大体逻辑为:必须有@Configuration修饰。然后解析一些Condition注解,看是否排除~
	if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
		return;
	}

    // 解析Scope
	ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
	abd.setScope(scopeMetadata.getScopeName());
    // 得到Bean的名称 一般为首字母小写(此处为AnnotationBeanNameGenerator)
	String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
    // 设定一些注解默认值,如lazy、Primary等等
	AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
    // 解析qualifiers,若有此注解  则primary都成为true了
	if (qualifiers != null) {
		for (Class<? extends Annotation> qualifier : qualifiers) {
			if (Primary.class == qualifier) {
				abd.setPrimary(true);
			}
			else if (Lazy.class == qualifier) {
				abd.setLazyInit(true);
			}
			else {
				abd.addQualifier(new AutowireCandidateQualifier(qualifier));
			}
		}
	}

    // 下面位解析Scope是否需要代理,最后把这个Bean注册进去
	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
	definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

三:refresh()  容器启动核心方法

2、包扫描的启动方式

public static void main(String[] args) {
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext("com.tuling.testspringiocstarter");
    System.out.println(ctx.getBean(TulingDao.class));
}

public AnnotationConfigApplicationContext(String... basePackages) {
	this();
	scan(basePackages);
	refresh();
}

public void scan(String... basePackages) {
	Assert.notEmpty(basePackages, "At least one base package must be specified");
	// 核心在这个scan方法里,见下面
	this.scanner.scan(basePackages);
}

/**
 * Perform a scan within the specified base packages.
 * @param basePackages the packages to check for annotated classes
 * @return number of beans registered 注册成功的bean个数
 */
public int scan(String... basePackages) {
	int beanCountAtScanStart = this.registry.getBeanDefinitionCount();

	doScan(basePackages);

	// Register annotation config processors, if necessary.
	if (this.includeAnnotationConfig) {
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

	return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}

重点看看doScan()方法

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
	Assert.notEmpty(basePackages, "At least one base package must be specified");
	// 装载扫描到的Bean
	Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
	for (String basePackage : basePackages) {

		// 这个方法是最重点,把扫描到的Bean就放进来了(比如此处只有RootConfig一个Bean定义,是个配置类)
		// 这个是重点,会把该包下面所有的Bean都扫描进去。Spring5和一下的处理方式不一样哦~
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
		for (BeanDefinition candidate : candidates) {
			// 拿到Scope元数据:此处为singleton
			ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
			candidate.setScope(scopeMetadata.getScopeName());
			// 生成Bean的名称,默认为首字母小写。此处为"rootConfig"
			String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);

			// 此处为扫描的Bean,为ScannedGenericBeanDefinition,所以肯定为true
			// 因此进来,执行postProcessBeanDefinition(对Bean定义信息做)   如下详解
			// 注意:只是添加些默认的Bean定义信息,并不是执行后置处理器~~~
			if (candidate instanceof AbstractBeanDefinition) {
				postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
			}
			// 显然,此处也是true  也是完善比如Bean上的一些注解信息:比如@Lazy、@Primary、@DependsOn、@Role、@Description   @Role注解用于Bean的分类分组,没有太大的作用
			if (candidate instanceof AnnotatedBeanDefinition) {
				AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
			}
			// 检查这个Bean  比如
			//如果dao包(一般配置的basePakage是这个)下的类是符合mybaits要求的则向spring IOC容器中注册它的BeanDefinition  所以这步检查第三方Bean的时候有必要检查一下
			if (checkCandidate(beanName, candidate)) {
				BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
				
				//AnnotationConfigUtils类的applyScopedProxyMode方法根据注解Bean定义类中配置的作用域@Scope注解的值,为Bean定义应用相应的代理模式,主要是在Spring面向切面编程(AOP)中使用
				definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
				beanDefinitions.add(definitionHolder);

				// 注意 注意 注意:这里已经吧Bean注册进去工厂了,所有doScan()方法不接收返回值,也是没有任何问题的。。。。
				registerBeanDefinition(definitionHolder, this.registry);
			}
		}
	}
	return beanDefinitions;
}

findCandidateComponents:根据basePackage扫描候选的组件们(非常重要)

public Set<BeanDefinition> findCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<BeanDefinition>();
	try {
		// 1.根据指定包名 生成包搜索路径
		//通过观察resolveBasePackage()方法的实现, 我们可以在设置basePackage时, 使用形如${}的占位符, Spring会在这里进行替换 只要在Enviroment里面就行
		// 本次值为:classpath*:com/fsx/config/**/*.class
		String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
				resolveBasePackage(basePackage) + '/' + this.resourcePattern;
		//2. 资源加载器 加载搜索路径下的 所有class 转换为 Resource[]
		// 拿着上面的路径,就可以getResources获取出所有的.class类,这个很强大~~~
		// 真正干事的为:PathMatchingResourcePatternResolver#getResources方法
		// 此处能扫描到两个类AppConfig(普通类,没任何注解标注)和RootConfig。所以接下里就是要解析类上的注解,以及过滤掉不是候选的类(比如AppConfig)
		
		// 注意:这里会拿到类路径下(不包含jar包内的)的所有的.class文件 可能有上百个,然后后面再交给后面进行筛选~~~~~~~~~~~~~~~~(这个方法,其实我们也可以使用)
		// 当然和getResourcePatternResolver和这个模版有关
		Resource[] resources = this.resourcePatternResolver.getResources(packageSearchPath);

		// 记录日志(下面我把打印日志地方都删除)
		boolean traceEnabled = logger.isTraceEnabled();
		boolean debugEnabled = logger.isDebugEnabled();
		for (Resource resource : resources) {
			if (traceEnabled) {
				logger.trace("Scanning " + resource);
			}
			if (resource.isReadable()) {
				try {
					//读取类的 注解信息 和 类信息 ,两大信息储存到  MetadataReader
					MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(resource);
					// 根据TypeFilter过滤排除组件。因为AppConfig没有标准@Component或者子注解,所以肯定不属于候选组件  返回false
					// 注意:这里一般(默认处理的情况下)标注了默认注解的才会true,什么叫默认注解呢?就是@Component或者派生注解。还有javax....的,这里省略啦
					if (isCandidateComponent(metadataReader)) {
						//把符合条件的 类转换成 BeanDefinition
						ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
						sbd.setResource(resource);
						sbd.setSource(resource);
						// 再次判断 如果是实体类 返回true,如果是抽象类,但是抽象方法 被 @Lookup 注解注释返回true (注意 这个和上面那个是重载的方法) 
						if (isCandidateComponent(sbd)) {
							if (debugEnabled) {
								logger.debug("Identified candidate component class: " + resource);
							}
							candidates.add(sbd);
						}
					}
				}
			}
		}
	}
	catch (IOException ex) {
		throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
	}
	return candidates;
}

ClassPathBeanDefinitionScanner#postProcessBeanDefinition

protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
	// Bean定义 设置默认的信息
	beanDefinition.applyDefaults(this.beanDefinitionDefaults);

	if (this.autowireCandidatePatterns != null) {
		beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
	}
}

就这样,扫描的Bean就全部注册完成了(若你的Config比较多的情况下,用扫描的方式更加简单些~)

最后

以上就是忐忑吐司为你收集整理的一、Spring IOC容器启动过程源码学习的全部内容,希望文章能够帮你解决一、Spring IOC容器启动过程源码学习所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(46)

评论列表共有 0 条评论

立即
投稿
返回
顶部