概要

Spring ApplicationContext在Web场景中的类图依赖如下:

class_diagram.png

Web应用中个,常用的实现类有: XmlWebApplicationAnnotationConfigWebApplicationContext.

BeanDefinition类图如下:

ScannedGenericBeanDefinition.png

XMLBean为GenericBeanDefinition,注解扫描的Bean为ScannedGenericBeanDefinition

refresh

ConfigurableApplicationContext的Refresh方法开始

  1. /**
  2. * Load or refresh the persistent representation of the configuration,
  3. * which might an XML file, properties file, or relational database schema.
  4. * <p>As this is a startup method, it should destroy already created singletons
  5. * if it fails, to avoid dangling resources. In other words, after invocation
  6. * of that method, either all or no singletons at all should be instantiated.
  7. * @throws BeansException if the bean factory could not be initialized
  8. * @throws IllegalStateException if already initialized and multiple refresh
  9. * attempts are not supported
  10. */
  11. void refresh() throws BeansException, IllegalStateException;

refresh方法会加载xml或其他形式的配置,完成bean实例化。

实现代码在AbstractApplicationContext中。

  1. @Override
  2. public void refresh() throws BeansException, IllegalStateException {
  3. synchronized (this.startupShutdownMonitor) {
  4. // Prepare this context for refreshing.
  5. prepareRefresh();
  6. // Tell the subclass to refresh the internal bean factory.
  7. ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
  8. // Prepare the bean factory for use in this context.
  9. prepareBeanFactory(beanFactory);
  10. try {
  11. // Allows post-processing of the bean factory in context subclasses.
  12. postProcessBeanFactory(beanFactory);
  13. // Invoke factory processors registered as beans in the context.
  14. invokeBeanFactoryPostProcessors(beanFactory);
  15. // Register bean processors that intercept bean creation.
  16. registerBeanPostProcessors(beanFactory);
  17. // Initialize message source for this context.
  18. initMessageSource();
  19. // Initialize event multicaster for this context.
  20. initApplicationEventMulticaster();
  21. // Initialize other special beans in specific context subclasses.
  22. onRefresh();
  23. // Check for listener beans and register them.
  24. registerListeners();
  25. // Instantiate all remaining (non-lazy-init) singletons.
  26. finishBeanFactoryInitialization(beanFactory);
  27. // Last step: publish corresponding event.
  28. finishRefresh();
  29. }
  30. catch (BeansException ex) {
  31. if (logger.isWarnEnabled()) {
  32. logger.warn("Exception encountered during context initialization - " +
  33. "cancelling refresh attempt: " + ex);
  34. }
  35. // Destroy already created singletons to avoid dangling resources.
  36. destroyBeans();
  37. // Reset 'active' flag.
  38. cancelRefresh(ex);
  39. // Propagate exception to caller.
  40. throw ex;
  41. }
  42. finally {
  43. // Reset common introspection caches in Spring's core, since we
  44. // might not ever need metadata for singleton beans anymore...
  45. resetCommonCaches();
  46. }
  47. }
  48. }

接下来进入一个个方法的内部细看。

prepareRefresh()

prepareRefresh方法:准备context,设置初始化的时间,与激活flag, 同时初始化属性源。
代码中用注释的形式标注

  1. /**
  2. * Prepare this context for refreshing, setting its startup date and
  3. * active flag as well as performing any initialization of property sources.
  4. */
  5. protected void prepareRefresh() {
  6. // Switch to active.
  7. this.startupDate = System.currentTimeMillis();
  8. this.closed.set(false); // 表示容器未关闭
  9. this.active.set(true); // 表示容器已激活
  10. // Initialize any placeholder property sources in the context environment.
  11. initPropertySources();
  12. }

obtainFreshBeanFactory

子类分别为XmlWebApplicationContext与AnnotationConfigWebApplicationContext,由子类各自实现获取刷新后的Bean工厂.

refreshBeanFactory

创建默认的DefaultListableBeanFactory(直接new),然后设置bean工厂的Id(对象hash地址. 然后执行loadBeanDefinitions载入工程中的Bean定义,如Xml配置的Bean,注解配置的Bean,两种混合使用的Bean.

xml load beandedinition

解析XML文件处理流程简要概括为:

  1. 判断每个xml node是否默认的命名空间:http://www.springframework.org/schema/beans,代码见`DefaultBeanDefinitionDocumentReader#parseBeanDefinitions`:

parse_xml_node.jpg

(处理XML node,tag的namespace会统一设置)

  1. 如果是beans这个命名空间下的元素则进入default的parse流程,解析beans,bean,importcontext:component-scancontext:annotation-config等xml元素标签。
    3)对于beans,beans,import采用xml node直接解析并创建为一个GenericBeanDefinition,然后包装为一个BeanDefinitionHolderBeanDefinitionHolder为一个典型的值对象,其关键定义如下:
  1. public class BeanDefinitionHolder implements BeanMetadataElement {
  2. private final BeanDefinition beanDefinition;
  3. private final String beanName;
  4. @Nullable
  5. private final String[] aliases;
  6. }

4)如果是自定义的命名空间,则采用自定义的解析流程。如context:xxx这种特殊标签,为Spring提供的命名空间,采用命名空间解析器来处理,用户可自定义命名空间,如dubbo:xxx.Spring内置了很多命名空间,如context:xxx, aop:xx,mvc:xx.
代码见:BeanDefinitionParserDelegate#parseCustomElement(org.w3c.dom.Element, org.springframework.beans.factory.config.BeanDefinition)

  1. public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
  2. String namespaceUri = getNamespaceURI(ele);
  3. if (namespaceUri == null) {
  4. return null;
  5. }
  6. NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
  7. return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
  8. }

解析NamespaceHandler采用的是配置加SPI的机制,DefaultNamespaceHandlerResolver把当前类路径下的META-INF/spring.handlers文件加载到一个Map中,Key为命名空间,Value为具体的处理类。
文件内容如下:

  1. http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
  2. http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
  3. http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
  4. http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler
  5. http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler

resolve时根据namespace uri查找Handler,并反射创建一个class,然后执行init,注册标签属性解析器。context:xxx的Handler示例如下:

  1. public class ContextNamespaceHandler extends NamespaceHandlerSupport {
  2. @Override
  3. public void init() {
  4. registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
  5. registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
  6. registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
  7. registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
  8. registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
  9. registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
  10. registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
  11. registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
  12. }
  13. }

annotation config load beandefinition

注解配置主要是配置扫描路径,Spring默认采用ClassPathBeanDefinitionScanner执行bean扫描。扫描带有@Component注解的class.然后注册到Bean工厂。

prepareBeanFactory(ConfigurableListableBeanFactory beanFactory)

1)准备bean工厂阶段,添加一些bean-post processor,如:ApplicationContextAwareProcessor(用来调用实现了XXXAware接口的bean的setXXX方法)
2) 添加ignoreDependencyInterfaces,如XXXAware接口(ApplicationContextAware), 如果实现了这些接口,表示不执行自动注入,当前prepare方法中有如下几个:

  1. // Configure the bean factory with context callbacks.
  2. beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
  3. beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
  4. beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
  5. beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
  6. beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
  7. beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
  8. beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

2)添加一些特殊接口,表示可自动注入到Bean中,如可注入一个BeanFactory,ApplicationContext实例,共有如下几个:

  1. // BeanFactory interface not registered as resolvable type in a plain factory.
  2. // MessageSource registered (and found for autowiring) as a bean.
  3. beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
  4. beanFactory.registerResolvableDependency(ResourceLoader.class, this);
  5. beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
  6. beanFactory.registerResolvableDependency(ApplicationContext.class, this);

invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) ??

  1. /**
  2. * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
  3. * respecting explicit order if given.
  4. * <p>Must be called before singleton instantiation.
  5. */
  6. protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
  7. PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
  8. // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
  9. // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
  10. if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
  11. beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
  12. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
  13. }
  14. }

registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory)

拦截Bean创建流程: Register bean processors that intercept bean creation.

Spring注册Bean阶段,会注册一些内部的post-processor, 如:CommonAnnotationBeanPostProcessor,AutowiredAnnotationBeanPostProcessor.

initMessageSource()

Initialize message source for this context.

initApplicationEventMulticaster()

Initialize event multicaster for this context. default is SimpleApplicationEventMulticaster

onRefresh()

Initialize other special beans in specific context subclasses.

registerListeners()

Check for listener beans and register them.

finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory)

Instantiate all remaining (non-lazy-init) singletons.

preInstantiateSingletons

Ensure that all non-lazy-init singletons are instantiated, also considering FactoryBeans
Typically invoked at the end of factory setup, if desired.

finishRefresh()

Finish the refresh of this context, invoking the LifecycleProcessor’s
onRefresh() method and publishing the event.

Bean的自定义初始化执行顺序

先执行 @PostConstruct 在执行 InitializingBean#afterPropertiesSet 最后执行XML配置的init方法

  1. protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
  2. invokeAwareMethods(beanName, bean);
  3. Object wrappedBean = bean;
  4. wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
  5. invokeInitMethods(beanName, wrappedBean, mbd);
  6. if (mbd == null || !mbd.isSynthetic()) {
  7. wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
  8. }
  9. return wrappedBean;
  10. }

invokeInitMethods方法如下:

  1. protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
  2. throws Throwable {
  3. boolean isInitializingBean = (bean instanceof InitializingBean);
  4. if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))){
  5. ((InitializingBean) bean).afterPropertiesSet();
  6. }
  7. if (mbd != null && bean.getClass() != NullBean.class) {
  8. String initMethodName = mbd.getInitMethodName();
  9. if (StringUtils.hasLength(initMethodName) &&
  10. !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
  11. !mbd.isExternallyManagedInitMethod(initMethodName)) {
  12. invokeCustomInitMethod(beanName, bean, mbd);
  13. }
  14. }
  15. }

Bean的生命周期

如何解决循环依赖

构造方法注入不支持循环依赖,Setter方法与字段注入支持循环依赖

构造方法注入会强校验bean是否为null,否则抛异常。因此构造方法注入场景出现循环依赖Spring抛出如下异常:

  1. Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'ABean': Requested bean is currently in creation: Is there an unresolvable circular reference?
  2. at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:798)

三级缓存

  1. DefaultSingletonBeanRegistry {
  2. /** Cache of singleton objects: bean name to bean instance. */
  3. // 创建完成的单例对象
  4. private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
  5. /** Cache of singleton factories: bean name to ObjectFactory. */
  6. // 单例对象工厂缓存
  7. private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
  8. /** Cache of early singleton objects: bean name to bean instance. */
  9. // 提前创建的bean
  10. private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
  11. /** Names of beans that are currently in creation. */
  12. // 正在创建的bean,还未创建完成
  13. private final Set<String> singletonsCurrentlyInCreation =
  14. Collections.newSetFromMap(new ConcurrentHashMap<>(16));
  15. }

如A依赖B,B依赖A. A,B的Bean都会被添加到singletonsCurrentlyInCreation.当创建B时,发现依赖A,则再次去getBean(A), 发现A正在创建,则抛BeanCurrentlyInCreationException异常。代码如下:

  1. /**
  2. * Callback before singleton creation.
  3. * <p>The default implementation register the singleton as currently in creation.
  4. * @param beanName the name of the singleton about to be created
  5. * @see #isSingletonCurrentlyInCreation
  6. */
  7. protected void beforeSingletonCreation(String beanName) {
  8. if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
  9. throw new BeanCurrentlyInCreationException(beanName);
  10. }
  11. }

Setter方法与字段注入产生的循环依赖,Spring是先创建Bean实例,一般直接反射创建一个class实例,内部的字段默认都是null,后续再执行依赖注入。通过@Autowired,@Resource内置的BeanPostProcessor完成注入。

对于Autowired注解,处理处理简要如下:

  1. AutowiredAnnotationBeanPostProcessor#postProcessProperties
  2. InjectionMetadata#inject
  3. InjectionMetadata具体实现有:AutowiredFieldElement,AutowiredMethodElement
  4. 注入方法的处理关键点为: 查找method,反射调用method#invoke
  1. ReflectionUtils.makeAccessible(method);
  2. method.invoke(bean, arguments);
  1. 注入字段的处理关键点为: 查找field,反射调用field#set
  1. ReflectionUtils.makeAccessible(field);
  2. field.set(bean, value);