【Spring cooking】厨师就位(一)AnnotationConfigApplicationContext

1. 背景介绍

启动一个基于 Spring 注解的容器,仅仅需要 new AnnotationConfigApplicationContext(),并传入自己的配置类。这短短一句话,威力却很大。我们就从这句话开始探索,它到底干了些什么

public class MainTest {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ConfigSwitch.class);
    }
}

AnnotationConfigApplicationContext 继承结构
请添加图片描述

2. 学习目标

  1. 了解 AnnotationConfigApplicationContext 及其父类实例化过程中做了哪些操作
  2. 了解 AnnotationConfigApplicationContext 及其父类的主要作用
  3. 明白 ApplicationContext 与 BeanFactory 的区别

3. 关键问题

  1. Environment 是什么时候注入 Spring 容器的

4. 源码追踪

AnnotationConfigApplicationContext

AnnotationConfigApplicationContext 及其父类

DefaultResourceLoader
		↑
AbstractApplicationContext
		↑
GenericApplicationContext 
		↑
AnnotationConfigApplicationContext

当执行 new AnnotationConfigApplicationContext(Class<?>... componentClasses)之前,会先执行父类的无参构造方法

  1. AbstractApplicationContext 初始化了 PathMatchingResourcePatternResolver
  2. GenericApplicationContext 初始化了最为重要的 DefaultListableBeanFactory

执行 new AnnotationConfigApplicationContext(Class<?>... componentClasses)

  1. this()
    初始化 AnnotatedBeanDefinitionReaderClassPathBeanDefinitionScanner

  2. register(componentClasses)
    实际是调用了 AnnotatedBeanDefinitionReader.register(Class<?>... componentClasses),请参考【Spring Cooking】厨师就位(二)AnnotatedBeanDefinitionReader注册配置类

  3. refresh()
    创建实例化对象

public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {

	public AnnotationConfigApplicationContext() {
		StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
		this.reader = new AnnotatedBeanDefinitionReader(this);
		createAnnotatedBeanDefReader.end();
		this.scanner = new ClassPathBeanDefinitionScanner(this);
	}

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

	@Override
	public void register(Class<?>... componentClasses) {
		Assert.notEmpty(componentClasses, "At least one component class must be specified");
		StartupStep registerComponentClass = this.getApplicationStartup().start("spring.context.component-classes.register")
				.tag("classes", () -> Arrays.toString(componentClasses));
		this.reader.register(componentClasses);
		registerComponentClass.end();
	}
}

AnnotatedBeanDefinitionReader

  1. AnnotatedBeanDefinitionReader 属性初始化

    AnnotationBeanNameGenerator
    AnnotationScopeMetadataResolver

  2. 执行有参构造

    1. getOrCreateEnvironment(registry) 触发 AbstractApplicationContext.createEnvironment()

    2. 初始化ConditionEvaluator,用来解析 @Conditional 注解

    3. 调用 AnnotationConfigUtils.registerAnnotationConfigProcessors 注册相关注解的后置处理器

public class AnnotatedBeanDefinitionReader {

	private final BeanDefinitionRegistry registry;

	private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;

	private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();

	private ConditionEvaluator conditionEvaluator;
	
	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;
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

	private static Environment getOrCreateEnvironment(BeanDefinitionRegistry registry) {
		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		if (registry instanceof EnvironmentCapable) {
			return ((EnvironmentCapable) registry).getEnvironment();
		}
		return new StandardEnvironment();
	}
}

AnnotationConfigUtils
  1. 查看 beanFactory.dependencyComparator 是否为 AnnotationAwareOrderComparator,不是的话则替换为 AnnotationAwareOrderComparator

  2. 查看 beanFactory.autowireCandidateResolver是否为 ContextAnnotationAutowireCandidateResolver,不是的话则替换为 ContextAnnotationAutowireCandidateResolver。此前为SimpleAutowireCandidateResolver,因此需要替换 ContextAnnotationAutowireCandidateResolver

  3. 注册五个内部组件的 BeanDefinition

    beanNamebeanClass
    org.springframework.context.annotation.internalConfigurationAnnotationProcessorConfigurationClassPostProcessor
    org.springframework.context.annotation.internalAutowiredAnnotationProcessorAutowiredAnnotationBeanPostProcessor
    org.springframework.context.annotation.internalCommonAnnotationProcessorCommonAnnotationBeanPostProcessor
    org.springframework.context.event.internalEventListenerProcessorEventListenerMethodProcessor
    org.springframework.context.event.internalEventListenerFactoryDefaultEventListenerFactory

    注册流程:

    1. new RootBeanDefinition(Class<?> beanClass)

    2. definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)

      namevaluedescription
      ROLE_APPLICATION0Role hint indicating that a BeanDefinition is a major part of the application. Typically corresponds to a user-defined bean.
      ROLE_SUPPORT1Role hint indicating that a BeanDefinition is a supporting part of some larger configuration, typically an outer org.springframework.beans.factory.parsing.ComponentDefinition. SUPPORT beans are considered important enough to be aware of when looking more closely at a particular org.springframework.beans.factory.parsing.ComponentDefinition, but not when looking at the overall configuration of an application.
      ROLE_INFRASTRUCTURE2Role hint indicating that a BeanDefinition is a major part of the application. Typically corresponds to a user-defined bean.
    3. BeanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition)

      beanName作为key,beanDefinition作为value,添加到DefaultListableBeanFactory.beanDefinitionMap, 并返回 BeanDefinitionHolder

    4. 将 BeanDefinitionHolder 添加到集合中

public abstract class AnnotationConfigUtils {

	public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
		registerAnnotationConfigProcessors(registry, null);
	}
	
	/**
	 * Register all relevant annotation post processors in the given registry.
	 * @param registry the registry to operate on
	 * @param source the configuration source element (already extracted)
	 * that this registration was triggered from. May be {@code null}.
	 * @return a Set of BeanDefinitionHolders, containing all bean definitions
	 * that have actually been registered by this call
	 */
	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));
		}

		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));
		}

		// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
		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.
		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));
		}

		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;
	}

	private static BeanDefinitionHolder registerPostProcessor(
			BeanDefinitionRegistry registry, RootBeanDefinition definition, String beanName) {

		definition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
		registry.registerBeanDefinition(beanName, definition);
		return new BeanDefinitionHolder(definition, beanName);
	}
}

ClassPathBeanDefinitionScanner

在这里插入图片描述
ClassPathBeanDefinitionScanner 构造方法调用了 registerDefaultFilters,往 includeFilters 添加

  1. AnnotationTypeFilter(Component.class)
  2. AnnotationTypeFilter(javax.annotation.ManagedBean)
  3. AnnotationTypeFilter(javax.inject.Named)
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {

	private final BeanDefinitionRegistry registry;

	private BeanDefinitionDefaults beanDefinitionDefaults = new BeanDefinitionDefaults();

	@Nullable
	private String[] autowireCandidatePatterns;

	private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;

	private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();

	private boolean includeAnnotationConfig = true;


	/**
	 * Create a new {@code ClassPathBeanDefinitionScanner} for the given bean factory.
	 * @param registry the {@code BeanFactory} to load bean definitions into, in the form
	 * of a {@code BeanDefinitionRegistry}
	 */
	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
		this(registry, true);
	}

	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
		this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
	}

	public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
			Environment environment) {

		this(registry, useDefaultFilters, environment,
				(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
	}

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

		Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
		this.registry = registry;

		if (useDefaultFilters) {
			registerDefaultFilters();
		}
		setEnvironment(environment);
		setResourceLoader(resourceLoader);
	}
}

public class ClassPathScanningCandidateComponentProvider implements EnvironmentCapable, ResourceLoaderAware {
	protected void registerDefaultFilters() {
		this.includeFilters.add(new AnnotationTypeFilter(Component.class));
		ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
		try {
			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 {
			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.
		}
	}
}

GenericApplicationContext

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
	public GenericApplicationContext() {
		this.beanFactory = new DefaultListableBeanFactory();
	}
}

DefaultListableBeanFactory

请添加图片描述
以下是 DefaultListableBeanFactory 及其父类的无参构造和属性

其中 AbstractAutowireCapableBeanFactory 初始化了 DefaultParameterNameDiscoverer 和 CglibSubclassingInstantiationStrategy

DefaultListableBeanFactory 赋值 SimpleAutowireCandidateResolver

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {

	/** Resolver to use for checking if a bean definition is an autowire candidate. */
	private AutowireCandidateResolver autowireCandidateResolver = SimpleAutowireCandidateResolver.INSTANCE;
	
	public DefaultListableBeanFactory() {
		super();
	}
}

public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
		implements AutowireCapableBeanFactory {
		
	/** Strategy for creating bean instances. */
	private InstantiationStrategy instantiationStrategy;

	/** Resolver strategy for method parameter names. */
	@Nullable
	private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

	/**
	 * Dependency interfaces to ignore on dependency check and autowire, as Set of
	 * Class objects. By default, only the BeanFactory interface is ignored.
	 */
	private final Set<Class<?>> ignoredDependencyInterfaces = new HashSet<>();

	public AbstractAutowireCapableBeanFactory() {
		super();
		ignoreDependencyInterface(BeanNameAware.class);
		ignoreDependencyInterface(BeanFactoryAware.class);
		ignoreDependencyInterface(BeanClassLoaderAware.class);
		if (NativeDetector.inNativeImage()) {
			this.instantiationStrategy = new SimpleInstantiationStrategy();
		}
		else {
			this.instantiationStrategy = new CglibSubclassingInstantiationStrategy();
		}
	}

	public void ignoreDependencyInterface(Class<?> ifc) {
		this.ignoredDependencyInterfaces.add(ifc);
	}
}

public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {

	/** ClassLoader to resolve bean class names with, if necessary. */
	@Nullable
	private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();

	/** BeanPostProcessors to apply. */
	private final List<BeanPostProcessor> beanPostProcessors = new BeanPostProcessorCacheAwareList();
	
	public AbstractBeanFactory() {}
}

AbstractApplicationContext

AbstractApplicationContext 实现了 ConfigurableEnvironment 接口,通过 createEnvironment() 来创建一个 StandardEnvironment

另外 AbstractApplicationContext 继承了 DefaultResourceLoader,拥有了加载类路径资源的能力。可以看到无参构造实际上就是去初始化去初始化 resourcePatternResolver,这里使用了装饰者模式 new PathMatchingResourcePatternResolver(this),实现了功能增强

public abstract class AbstractApplicationContext extends DefaultResourceLoader
		implements ConfigurableApplicationContext {
	public AbstractApplicationContext() {
		this.resourcePatternResolver = getResourcePatternResolver();
	}

	protected ResourcePatternResolver getResourcePatternResolver() {
		return new PathMatchingResourcePatternResolver(this);
	}

	@Override
	public ConfigurableEnvironment getEnvironment() {
		if (this.environment == null) {
			this.environment = createEnvironment();
		}
		return this.environment;
	}

	protected ConfigurableEnvironment createEnvironment() {
		return new StandardEnvironment();
	}
}

PathMatchingResourcePatternResolver

请添加图片描述
这里用到了装饰者模式,可以看到 PathMatchingResourcePatternResolver 的有参构造所用的参数是其顶层接口 ResourceLoader ,类似 new BufferedInputStream(InputStream)

后续在 @ComponentScan 扫描的时候会调用 getResources(String locationPattern)来获取 Class 文件

public class PathMatchingResourcePatternResolver implements ResourcePatternResolver {
	public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
		Assert.notNull(resourceLoader, "ResourceLoader must not be null");
		this.resourceLoader = resourceLoader;
	}
}

DefaultResourceLoader

public class DefaultResourceLoader implements ResourceLoader {
	public DefaultResourceLoader() {}
}

5. 结论

先看学习目标是否达成

  1. 了解 AnnotationConfigApplicationContext 及其父类实例化过程中做了哪些操作

    AbstractApplicationContext 实例化创建了 PathMatchingResourcePatternResolver

    GenericApplicationContext 实例化创建了 DefaultListableBeanFactory

    AnnotationConfigApplicationContext 实例化创建了 AnnotatedBeanDefinitionReader 和 ClassPathBeanDefinitionScanner

    其中 AnnotatedBeanDefinitionReader 在实例化过程中触发了 Environment 的创建,并注册了五个重要内部组件的 BeanDefinition

  2. 了解 AnnotationConfigApplicationContext 及其父类的主要作用

    AnnotationConfigApplicationContext

    独立的ApplicationContext,可以注册 @Configuration,@Component和JSR-330规范注解的类

    可以通过register(Class…)来注册Class,或者scan(String…)来扫描类路径

    当前注册的BeanDefinition会被后续解析的@Configuration或者@Bean方法覆盖

    GenericApplicationContext

    继承自 AbstractApplicationContext,可以加载各种配置文件,例如xml,properties等等。

    持有一个 DefaultListableBeanFactory 实例,并且在启动的时候已经准备好了。

    refresh() 只被调用一次。与之相反的是 AbstractRefreshableApplicationContext

    实现了 BeanDefinitionRegistry 接口,这样 BeanAnnotationReader 运用它来读取 BeanDefinition,像本篇文章的 AnnotatedBeanDefinitionReader ,还有后续会提及的 ConfigurationClassBeanDefinitionReader,XmlBeanDefinitionReader,PropertiesBeanDefinitionReader

    典型的用法是通过 BeanDefinitionRegistry 接口注册各种bean定义,然后调用refresh() 来使用 ApplicationContext 语义初始化这些bean。

    GenericApplicationContext ctx = new GenericApplicationContext();
    
    XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
    xmlReader.loadBeanDefinitions(new ClassPathResource("applicationContext.xml"));
    
    PropertiesBeanDefinitionReader propReader = new PropertiesBeanDefinitionReader(ctx);
    propReader.loadBeanDefinitions(new ClassPathResource("otherBeans.properties"));
    
    ctx.refresh();
    MyBean myBean = (MyBean) ctx.getBean("myBean");
    

    From chat with Bing
    GenericApplicationContext 的优势是它可以灵活地使用不同的 bean 定义格式和资源位置,而不受限于标准的 XML 文件或注解。它也可以在一开始就获取到内部的 BeanFactory 实例,而不需要等待刷新操作。这样可以提高性能和灵活性。

    AbstractApplicationContext

    ApplicationContext 接口的抽象实现类,使用的是模板方法设计模式,子类需要实现以下方法
    void refreshBeanFactory()
    void closeBeanFactory()
    ConfigurableListableBeanFactory getBeanFactory()

    与 BeanFactory 不同,ApplicationContext 应该可以检测其内部 BeanFactory 定义的特殊bean。要完成这项工作,则需要以下三个组件的加持

    • BeanFactoryPostProcessors
    • BeanPostProcessors
    • ApplicationListeners

    AbstractApplicationContext 还额外提供两个 bean

    • MessageSource
    • ApplicationEventMulticaster

    继承 DefaultResourceLoader 来实现资源加载

    DefaultResourceLoader

    ResourceLoader 的默认实现,ResourceEditor 的成员变量

    定位的资源如果是URL,则返回UrlResource;如果是非URL或者“classpath:”,则返回 ClassPathResource

  3. 明白 ApplicationContext 与 BeanFactory 的区别

6. 注意细节

7. 待研究

  1. PathMatchingResourcePatternResolver 是如何加载资源文件

8. 推荐文章

Spring源码阅读-ApplicationContext体系结构分析
Spring源码阅读-IoC容器解析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值