Spring:Spring IOC注解方式注册beanDefinition

1.美图

2.概述

梳理Spring 容器启动时,注解bean 加载的主流程和相关核心逻辑。

3.案例

3.1 案例1

bean

package com.spring.boot.annotation;

import lombok.Data;

@Data
public class TestBean {
    private String name;
}

初始化string bean

package com.spring.boot.annotation;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
class NameConfig {

    @Bean
    String name() { return "foo"; }
}

配置

package com.spring.boot.annotation;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import(NameConfig.class)
//@Import(AspectJAutoProxyRegistrar.class)
//@ImportResource("org/springframework/aop/aspectj/AfterAdviceBindingTests.xml")
class AutowiredConfig {

    @Autowired
    private String name;

    @Bean
    TestBean testBean() {
        TestBean testBean = new TestBean();
        testBean.setName(name);
        return testBean;
    }
}

测试类

package com.spring.boot.annotation;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;

import java.util.Map;

import static org.junit.Assert.*;
import static org.springframework.util.StringUtils.uncapitalize;

public class NameConfigTest {

    @Test
    public void scanAndRefresh() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.scan("org.springframework.context.annotation6");
        context.refresh();

//        context.getBean(uncapitalize(ConfigForScanning.class.getSimpleName()));
//        context.getBean("testBean"); // contributed by ConfigForScanning
//        context.getBean(uncapitalize(ComponentForScanning.class.getSimpleName()));
//        context.getBean(uncapitalize(Jsr330NamedForScanning.class.getSimpleName()));
        Map<String, Object> beans = context.getBeansWithAnnotation(Configuration.class);
        assertEquals(1, beans.size());
    }

    @Test
    public void registerAndRefresh() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(AutowiredConfig.class);
        //context.register(Config.class, NameConfig.class);
        context.refresh();

        context.getBean("testBean");
        context.getBean("name");
        Map<String, Object> beans = context.getBeansWithAnnotation(Configuration.class);
        assertEquals(2, beans.size());
    }

}

4.容器初始化

先说明几个在Spring 初始化容器中非常重要的对象

  1. BeanDefinition 对象:容器中的每一个 bean 都会有一个对应的 BeanDefinition 实例。该实例负责保存 bean 对象的所有必要信息,包括 bean 对象的 class 类型、是否是抽象类、构造方法和参数、其他属性等等。
  2. BeanDefinitionRegistry 对象: 抽象出 bean 的注册逻辑。registerBeanDefinition、removeBeanDefinition、getBeanDefinition 等注册管理 BeanDefinition 的方法。
  3. BeanFactory 对象: 则抽象出了 bean 的管理逻辑。主要包含 getBean、containBean、getType、getAliases 等管理 bean 的方法。
  4. DefaultListableBeanFactory 对象: 作为一个比较通用的 BeanFactory 实现,它同时也实现了 BeanDefinitionRegistry 接口,因此它就承担了 bean 的注册管理工作,这是常用的注册管理bean 的beanFactory。

5.AnnotationConfigApplicationContext

public AnnotationConfigApplicationContext() {
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}
	public AnnotationConfigApplicationContext(DefaultListableBeanFactory beanFactory) {
		super(beanFactory);
		this.reader = new AnnotatedBeanDefinitionReader(this);
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

	//直接将注解bean注册到容器,通过将涉及到的配置类传递给该构造函数,以实现将相应配置类中的Bean自动注册到容器中
	public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
		this();
		register(annotatedClasses);
		refresh();
	}
}

从源码中可以看出,空参的构造方法会先初始化sacner和reader,为进行bean的解析注册做准备,而容器里不包含任何Bean信息,从注释

/**
     * Create a new AnnotationConfigApplicationContext that needs to be populated
     * through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
 */
 

可以看出,如果调用空参构造,需要手动调用其register()方法注册配置类,并调用refresh()方法刷新容器,触发容器对注解Bean的载入、解析和注册过程。

而BeanFactory是在哪里初始化的呢?

AnnotationConfigApplicationContext父类中,可以找到beanFactory的初始化。

GenericApplicationContext#new
public GenericApplicationContext() {
	this.beanFactory = new DefaultListableBeanFactory();
}

new DefaultListableBeanFactory()过程中会初始化所有父类的属性以及加载各种配置,如beanClassLoader,InstantiationStrategy等。

然后在初始化AnnotatedBeanDefinitionReader过程中,会初始化spring inner-post-processor,包括BeanPostProcessorBeanFactoryPostProcessor(比如

ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor)。
AnnotatedBeanDefinitionReader#new

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
		this.registry = registry;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}
	

AnnotationConfigUtils#registerAnnotationConfigProcessors

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {

		DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
		if (beanFactory != null) {
			if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
				beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
			}
			if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
				beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
			}
		}

		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

		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));
		}
		...
		return beanDefs;
}

而在初始化ClassPathBeanDefinitionScanner时,会注册过滤器,也就是需要扫描什么注解,比如@Component

protected void registerDefaultFilters() {
		//向要包含的过滤规则中添加@Component注解类,注意Spring中@Repository
		//@Service和@Controller都是Component,因为这些注解都添加了@Component注解
		this.includeFilters.add(new AnnotationTypeFilter(Component.class));
		//获取当前类的类加载器
		ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
		try {
			//向要包含的过滤规则添加JavaEE6的@ManagedBean注解
			this.includeFilters.add(new AnnotationTypeFilter(
					((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
			logger.trace("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 {
			//向要包含的过滤规则添加@Named注解
			this.includeFilters.add(new AnnotationTypeFilter(
					((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
			logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
		}
		catch (ClassNotFoundException ex) {
			// JSR-330 API not available - simply skip.
		}
	}

此时容器的初始化完成。开始注册bean Definition

5.1 registerBean

Spring 提供两种bean的注册方式,一种时通过扫描路径来加载,另一种则是通过class文件来注册。先来看下class文件注册。

5.1.1 class文件注册

@Test
public void registerAndRefresh() {
	AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
	context.register(AutowiredConfig.class);
	context.refresh();

	context.getBean("testBean");
	context.getBean("name");
	Map<String, Object> beans = context.getBeansWithAnnotation(Configuration.class);
	assertEquals(2, beans.size());
}

主要看context.register(AutowiredConfig.class)方法,主要流程如下:

在这里插入图片描述

5.1.2 AnnotationBeanDefinitionReader#doRegisterBean

<T> void doRegisterBean(Class<T> beanClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

		//根据指定的注解Bean定义类,创建Spring容器中对注解Bean的封装的数据结构
		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
		//用来解析注释了@condition注解的类,不满足条件跳过
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}

		//设置创建bean实例的回调
		abd.setInstanceSupplier(instanceSupplier);
		//解析注解Bean定义的作用域
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		//为注解Bean定义设置作用域
		abd.setScope(scopeMetadata.getScopeName());
		//为注解Bean生成Bean名称
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

		//处理注解Bean定义中的通用注解
		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

		//如果在向容器注册注解Bean定义时,使用了额外的限定符注解,则解析限定符注解。
		//主要是配置的关于autowiring自动依赖注入装配的限定条件,即@Qualifier注解,Spring自动依赖注入装配默认是按类型装配,
		// 如果使用@Qualifier则按名称
		if (qualifiers != null) {
			for (Class<? extends Annotation> qualifier : qualifiers) {
				//如果配置了@Primary注解,设置该Bean为autowiring自动依赖注入装配时的首选
				if (Primary.class == qualifier) {
					abd.setPrimary(true);
				}
				//如果配置了@Lazy注解,则设置该Bean为非延迟初始化,如果没有配置,则该Bean为预实例化
				else if (Lazy.class == qualifier) {
					abd.setLazyInit(true);
				}
				else {
					//如果使用了除@Primary和@Lazy以外的其他注解,则为该Bean添加一
					//个autowiring自动依赖注入装配限定符,该Bean在进autowiring
					//自动依赖注入装配时,根据名称装配限定符指定的Bean
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}
		for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
			customizer.customize(abd);
		}

		//创建一个指定Bean名称的Bean定义对象,封装注解Bean定义类数据
		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
		//根据注解Bean定义类中配置的作用域,创建相应的代理对象
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
		//向IoC容器注册注解Bean类定义对象
		BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

可以看出,就是将annotatedClass解析成BeanDefinition,并将bean的属性例如@Lazy等封装进去,接着调用beanFactory的注册:
DefaultListableBeanFactory#registerBeanDefinition

/**
	 * 向IOC容器注册解析的BeanDefiniton
	 * @param beanName the name of the bean instance to register
	 * @param beanDefinition definition of the bean instance to register
	 * @throws BeanDefinitionStoreException
	 */
	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		Assert.hasText(beanName, "Bean name must not be empty");
		Assert.notNull(beanDefinition, "BeanDefinition must not be null");

		//校验解析的BeanDefiniton,如果beanDefinition是AbstractBeanDefinition实例,则验证
		if (beanDefinition instanceof AbstractBeanDefinition) {
			try {
				//验证不能将静态工厂方法与方法重写相结合(静态工厂方法必须创建实例) 此处的检验是针对AbstractBeanDefinition的属性methodOverrides的检验
				((AbstractBeanDefinition) beanDefinition).validate();
			}
			catch (BeanDefinitionValidationException ex) {
				throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
						"Validation of bean definition failed", ex);
			}
		}

		// 2、优先尝试从缓存中加载BeanDefinition
		BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
		if (existingDefinition != null) {
			// beanName已经存在且不允许被覆盖,抛出异常
			if (!isAllowBeanDefinitionOverriding()) {
				throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
			}
			// 使用新的BeanDefinition覆盖已经加载的BeanDefinition,if else中只有日志打印,无实质代码,删除为了阅读方便
			else if (existingDefinition.getRole() < beanDefinition.getRole()) {
				// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
				if (logger.isInfoEnabled()) {
					logger.info("Overriding user-defined bean definition for bean '" + beanName +
							"' with a framework-generated bean definition: replacing [" +
							existingDefinition + "] with [" + beanDefinition + "]");
				}
			}
			//覆盖 beanDefinition 与 被覆盖的 beanDefinition 不相同,打印 debug 日志
			else if (!beanDefinition.equals(existingDefinition)) {
				if (logger.isDebugEnabled()) {
					logger.debug("Overriding bean definition for bean '" + beanName +
							"' with a different definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			//其他的,都打印debug日志
			else {
				if (logger.isTraceEnabled()) {
					logger.trace("Overriding bean definition for bean '" + beanName +
							"' with an equivalent definition: replacing [" + existingDefinition +
							"] with [" + beanDefinition + "]");
				}
			}
			//允许覆盖,直接覆盖原有的 BeanDefinition 到 beanDefinitionMap 中。
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		// 3、缓存中无对应的BeanDefinition,则直接注册
		else {
			// 如果beanDefinition已经被标记为创建(为了解决单例bean的循环依赖问题)
			if (hasBeanCreationStarted()) {
				// Cannot modify startup-time collection elements anymore (for stable iteration)
				//注册的过程中需要线程同步,以保证数据的一致性
				synchronized (this.beanDefinitionMap) {
					// 将beanDefinition保存到beanDefinitionMap中
					this.beanDefinitionMap.put(beanName, beanDefinition);
					// 创建List<String>并将缓存的beanDefinitionNames和新解析的beanName加入集合,对beanDefinitionNames进行重新的扩容操作
					List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
					//添加扩容之前的
					updatedDefinitions.addAll(this.beanDefinitionNames);
					//添加beanName到updatedDefinitions中
					updatedDefinitions.add(beanName);
					// 将updatedDefinitions赋值给beanDefinitionNames
					this.beanDefinitionNames = updatedDefinitions;
					// 如果manualSingletonNames中包含新注册的beanName
					removeManualSingletonName(beanName);
				}
			}
			else {
				// Still in startup registration phase
				// 将beanDefinition信息维护至缓存
				// beanDefinitionMap-->(key->beanName,value->beanDefinition)
				this.beanDefinitionMap.put(beanName, beanDefinition);
				// beanDefinitionNames-->维护了beanName集合
				this.beanDefinitionNames.add(beanName);
				// manualSingletonNames缓存了手动注册的单例bean,所以需要调用一下remove方法,防止beanName重复
				// 例如:xmlBeanFactory.registerSingleton("myDog", new Dog());
				// 就可以向manualSingletonNames中注册单例bean
				removeManualSingletonName(beanName);
			}
			this.frozenBeanDefinitionNames = null;
		}

		//检查是否有同名的BeanDefinition已经在IOC容器中注册
		// 4、重置BeanDefinition,
		// 当前注册的bean的定义已经在beanDefinitionMap缓存中存在,
		// 或者其实例已经存在于单例bean的缓存中
		if (existingDefinition != null || containsSingleton(beanName)) {
			//重置所有已经注册过的BeanDefinition的缓存
			resetBeanDefinition(beanName);
		}
	}

BeanDefinition的注册分为步:

  1. 从缓存中取出当前bean的BeanDefinition
  2. 如果存在,则用当前BeanDefinition覆盖原有的
  3. 如果不存在,判断当前bean是否以及开始创建
  4. 如果没有开始创建,则将当前BeanDefinition,以及beanName放入缓存
  5. 如果已经开始创建,将当前BeanDefinition和beanName放入缓存后,如果当前bean是manual singleton bean,则将当前beanName从manual singleton Bean Name中移出,也就是变成了普通的bean,这里的manual singleton Bean指的是以下几种bean:

5.2 scanBean方式

新建类

package com.spring.boot.annotation;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ConfigForScanning {
    @Bean
    public TestBean testBean() {
        return new TestBean();
    }
}

package com.spring.boot.annotation;

import org.springframework.stereotype.Component;

@Component
public class ComponentForScanning {
}

package com.spring.boot.annotation;

import javax.inject.Named;

@Named
public class Jsr330NamedForScanning {

}

测试类

 @Test
    public void scanAndRefresh() {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.scan("com.spring.boot.annotation");
        context.refresh();

        context.getBean(uncapitalize(ConfigForScanning.class.getSimpleName()));
        context.getBean("testBean"); // contributed by ConfigForScanning
        context.getBean(uncapitalize(ComponentForScanning.class.getSimpleName()));
        context.getBean(uncapitalize(Jsr330NamedForScanning.class.getSimpleName()));
        Map<String, Object> beans = context.getBeansWithAnnotation(Configuration.class);
        assertEquals(1, beans.size());
    }

还是先看context.scan()方法。主要流程如下:

在这里插入图片描述

5.2.1 ClassPathBeanDefinitionScanner#doScan

protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
		Assert.notEmpty(basePackages, "At least one base package must be specified");
		Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
		for (String basePackage : basePackages) {
			//扫描给定类路径,获取符合条件的Bean定义
			Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
			for (BeanDefinition candidate : candidates) {
				//获取Bean定义类中@Scope注解的值,即获取Bean的作用域
				ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
				candidate.setScope(scopeMetadata.getScopeName());
				//生成bean name
				String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
				//如果扫描到的Bean不是Spring的注解Bean,则为Bean设置默认值,
				//设置Bean的自动依赖注入装配属性等
				if (candidate instanceof AbstractBeanDefinition) {
					postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
				}
				//如果扫描到的Bean是Spring的注解Bean,则处理其通用的Spring注解
				if (candidate instanceof AnnotatedBeanDefinition) {
					//处理注解Bean中通用的注解
					AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
				}
				//根据Bean名称检查指定的Bean是否需要在容器中注册,或者在容器中冲突
				if (checkCandidate(beanName, candidate)) {
					BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
					//根据注解中配置的作用域,为Bean应用相应的代理模式
					definitionHolder =
							AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
					beanDefinitions.add(definitionHolder);
					registerBeanDefinition(definitionHolder, this.registry);
				}
			}
		}
		return beanDefinitions;
	}
	

这个其实和registerBean差不多,只是多了一步从扫描路径里获取符合的bean并封装到beanDefinition中,然后就是registerBean的流程

ClassPathScanningCandidateComponentProvider#scanCandidateComponents

private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		try {
			//解析给定的包路径,this.resourcePattern=” **/*.class”,
			//ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX=“classpath:”
			//resolveBasePackage方法将包名中的”.”转换为文件系统的”/”
			String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
					resolveBasePackage(basePackage) + '/' + this.resourcePattern;
			//将给定的包路径解析为Spring资源对象
			Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
			boolean traceEnabled = logger.isTraceEnabled();
			boolean debugEnabled = logger.isDebugEnabled();
			for (Resource resource : resources) {
				if (traceEnabled) {
					logger.trace("Scanning " + resource);
				}
				if (resource.isReadable()) {
					try {
						//为指定资源获取元数据读取器,元信息读取器通过汇编(ASM)读取资源元信息
						MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
						//如果扫描到的类符合容器配置的过滤规则
						if (isCandidateComponent(metadataReader)) {
							//通过汇编(ASM)读取资源字节码中的Bean定义元信息
							ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
							//设置Bean定义来源于resource
							sbd.setResource(resource);
							//为元数据元素设置配置资源对象
							sbd.setSource(resource);
							//检查Bean是否是一个可实例化的对象
							if (isCandidateComponent(sbd)) {
								if (debugEnabled) {
									logger.debug("Identified candidate component class: " + resource);
								}
								candidates.add(sbd);
							}
							else {
								if (debugEnabled) {
									logger.debug("Ignored because not a concrete top-level class: " + resource);
								}
							}
						}
						else {
							if (traceEnabled) {
								logger.trace("Ignored because not matching any filter: " + resource);
							}
						}
					}
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to read candidate component class: " + resource, ex);
					}
				}
				else {
					if (traceEnabled) {
						logger.trace("Ignored because not readable: " + resource);
					}
				}
			}
		}
		catch (IOException ex) {
			throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
		}
		return candidates;
	}


发布了1089 篇原创文章 · 获赞 451 · 访问量 136万+

猜你喜欢

转载自blog.csdn.net/qq_21383435/article/details/104160702