使用 spring 5.1.19.RELEASE 分析
整个 IoC 容器都是围绕着 BeanFactory
和 ApplicationContext
来设计的。BeanFactory
提供了容器的基本功能。ApplicationContext
继承自 BeanFactory
,不光实现了容器的基本功能,还实现了一些更高级的容器特性。
BeanFactory 容器设计
这是一条主要的 BeanFactory
设计路线。
BeanFactory
提供了如 getBean
这样的基本方法用来获取容器中的 bean。
HierarchicalBeanFactory
提供了 getParentBeanFactory
方法,使得容器获得了父子容器管理的功能。
SingletonBeanRegistry
提供了管理单例 bean 的功能。
ConfigurableBeanFactory
提供了一些容器的配置功能,比如设置容器的父容器的 setParentBeanFactory
方法。
在这条路线上,有一个实现了基本容器功能的类 DefaultListableBeanFactory
。
DefaultListableBeanFactory
已经实现了容器的基本功能,也就是说我们可以直接使用它了。该类还有一个子类 XmlBeanFactory
,不过已经不推荐使用了。
1 2 3 4 5 6 7 8 9 10 11 12 13 @Deprecated @SuppressWarnings({"serial", "all"}) public class XmlBeanFactory extends DefaultListableBeanFactory { private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader (this ); public XmlBeanFactory (Resource resource) throws BeansException { this (resource, null ); } public XmlBeanFactory (Resource resource, BeanFactory parentBeanFactory) throws BeansException { super (parentBeanFactory); this .reader.loadBeanDefinitions(resource); } }
通过查看 XmlBeanFactory
的代码,我们可以模仿它来使用 DefaultListableBeanFactory
。
1 2 3 4 5 6 7 8 9 10 11 12 public static void main (String[] args) { ClassPathResource classPathResource = new ClassPathResource ("applicationContext.xml" ); DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory (); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader (defaultListableBeanFactory); reader.loadBeanDefinitions(classPathResource); ElectricCar electricCar = (ElectricCar) defaultListableBeanFactory.getBean("electricCar" ); }
ApplicationContext 容器设计 IoC 容器的第二条设计路线以 ApplicationContext
接口为主,在继承了 BeanFactory
的同时,还继承了 MessageSource
、ApplicationEventPublisher
、ResourceLoader
等接口。
ApplicationContext
作为 BeanFactory
的实现,和 XmlBeanFactory
一样,也是在 DefaultListableBeanFactory
这个基本的容器实现上做扩展(一般是通过持有一个 DefaultListableBeanFactory
对象来实现)。我们常用的应用上下文基本上都是 ConfigurableApplicationContext
或者 WebApplicationContext
的实现。
实现了 ConfigurableApplicationContext 接口的类
描述
FileSystemXmlApplicationContext
通过文件系统加载 xml 配置文件来初始化容器
ClassPathXmlApplicationContext
通过 classpath 加载 xml 配置文件来初始化容器
AnnotationConfigApplicationContext
通过加载纯注解的配置类来初始化容器
实现了 WebApplicationContext 接口的类
描述
AnnotationConfigWebApplicationContext
通过加载纯注解的配置类来初始化具有 Web 功能的容器
XmlWebApplicationContext
在 Web 应用中,我们一般会在 web.xml 中设置一个监听器:ContextLoaderListener,默认情况下,它会在 Servlet 容器启动时创建并初始化一个 XmlWebApplicationContext
容器初始化过程 IoC 容器的初始化是通过 AbstractApplicationContext
的 refresh
方法来完成的,这个过程主要包括 BeanDefinition 的 Resource 定位、载入和注册三个基本操作,Spring 将这三个过程分开,使用了不同的模块来完成(比如使用 ResourceLoader、BeanDefinitionReader 等)。通过这种方式,可以让用户根据需要更加灵活地对这三个过程进行修改或者扩展。
包含 BeanDefinition 的资源定位 我们知道,BeanDefinition 接口是 Bean 定义的抽象,用来描述 Bean 的一些信息,比如是单例 Bean 还是原型 Bean,对应的类的全限定名称,是否需要延迟初始化,依赖关系等等。Bean 定义的存在形式有很多种,常见的可能会在文件系统中或者在类路径中,因此,Spring 抽象出了 Resource 接口,在文件系统中的 Bean 定义资源就可以通过 FileSystemResource 来抽象,而在类路径的 Bean 定义资源则可以通过 ClassPathResource 来抽象,然后它们都可以通过对应的 ResourceLoader 来获取。
在以编程的方式使用 DefaultListableBeanFactory 时,我们需要定义一个 Resource 来定位容器所使用的 Bean 定义资源,这里的 Resource 并不能直接交给 DefaultListableBeanFactory 使用,因为 DefaultListableBeanFactory 只是一个单纯的 IoC 容器,我们需要为它配置一个特定的 BeanDefinitionReader,用来读取 Bean 定义资源,并将 Bean 定义转换成容器能够处理的形式。而我们使用的很多 ApplicationContext 实现中已经提供了一系列能够加载不同 Resource 的读取器实现,我们以 FileSystemXmlApplicationContext 为例,从头到尾梳理一下容器的初始化过程。
通过上图可以看出,FileSystemXmlApplicationContext 通过继承 AbstractApplicationContext,具备了 ResourceLoader 读取 Resource 的能力。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext { public FileSystemXmlApplicationContext () { } public FileSystemXmlApplicationContext (ApplicationContext parent) { super (parent); } public FileSystemXmlApplicationContext (String configLocation) throws BeansException { this (new String [] {configLocation}, true , null ); } public FileSystemXmlApplicationContext ( String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException { super (parent); setConfigLocations(configLocations); if (refresh) { refresh(); } } @Override protected Resource getResourceByPath (String path) { if (path.startsWith("/" )) { path = path.substring(1 ); } return new FileSystemResource (path); } }
在最后这个构造器中调用了父类的构造器,我们沿着类图一直向上,能够追溯到 AbstractApplicationContext 类:
1 2 3 4 5 6 7 8 9 10 11 12 13 public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext { public AbstractApplicationContext () { this .resourcePatternResolver = getResourcePatternResolver(); } public AbstractApplicationContext (@Nullable ApplicationContext parent) { this (); setParent(parent); } protected ResourcePatternResolver getResourcePatternResolver () { return new PathMatchingResourcePatternResolver (this ); } }
可以看到,在 AbstractApplicationContext 中初始化了一个 PathMatchingResourcePatternResolver 类,它实现了 ResourcePatternResolver 接口。我们知道,Resource 是资源的抽象,通过它可以访问各种包含 Bean 定义的资源,但是该接口有一个问题:它不支持以通配符的方式读取资源。如果我们要访问同一个路径下所有符合条件的资源,只能将读取的资源路径全部写出来才可以,ResourcePatternResolver 的出现就是为了解决这个问题的,它能够按照相应的模式匹配策略将资源路径转换成对应的资源,默认情况下使用的 PathMatchingResourcePatternResolver 是按照 Ant 风格的匹配策略来处理资源路径的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public void setConfigLocations (@Nullable String... locations) { if (locations != null ) { Assert.noNullElements(locations, "Config locations must not be null" ); this .configLocations = new String [locations.length]; for (int i = 0 ; i < locations.length; i++) { this .configLocations[i] = resolvePath(locations[i]).trim(); } } else { this .configLocations = null ; } } protected String resolvePath (String path) { return getEnvironment().resolveRequiredPlaceholders(path); }
我们接着回到 setConfigLocations 方法。在该方法中,resolvePath 方法能够将资源路径字符串中的占位符转换成对应的值。比如资源路径为:classpath:applicationContext-${profile}.xml
,那么该方法会从环境变量(包括系统变量、用户自定义的变量等)中寻找对应的值进行替换。
对于容器的启动来说,refresh 方法是一个很重要的方法,它详细地描述了整个 ApplicationContext 的初始化过程,比如 BeanFactory 的刷新,MessageSource 和 PostProcessor 的注册等等,这个执行过程为 Bean 的生命周期管理创造了条件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 @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(); } catch (BeansException ex) { if (logger.isWarnEnabled()) { logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex); } destroyBeans(); cancelRefresh(ex); throw ex; } finally { resetCommonCaches(); } } }
在这里,我们需要重点关注 obtainFreshBeanFactory 方法。
1 2 3 4 5 6 7 8 9 10 protected ConfigurableListableBeanFactory obtainFreshBeanFactory () { refreshBeanFactory(); ConfigurableListableBeanFactory beanFactory = getBeanFactory(); if (logger.isDebugEnabled()) { logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory); } return beanFactory; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @Override protected final void refreshBeanFactory () throws BeansException { if (hasBeanFactory()) { destroyBeans(); closeBeanFactory(); } try { DefaultListableBeanFactory beanFactory = createBeanFactory(); beanFactory.setSerializationId(getId()); customizeBeanFactory(beanFactory); loadBeanDefinitions(beanFactory); synchronized (this .beanFactoryMonitor) { this .beanFactory = beanFactory; } } catch (IOException ex) { throw new ApplicationContextException ("I/O error parsing bean definition source for " + getDisplayName(), ex); } }
Spring 在刷新 BeanFactory 时,会检测 BeanFactory 是否已经创建,已经创建会执行销毁方法,然后重新创建。在 BeanFactory 创建完成后,会开始加载并解析 bean 的配置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 protected void loadBeanDefinitions (DefaultListableBeanFactory beanFactory) throws BeansException, IOException { XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader (beanFactory); beanDefinitionReader.setEnvironment(this .getEnvironment()); beanDefinitionReader.setResourceLoader(this ); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver (this )); initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); } protected void loadBeanDefinitions (XmlBeanDefinitionReader reader) throws BeansException, IOException { Resource[] configResources = getConfigResources(); if (configResources != null ) { reader.loadBeanDefinitions(configResources); } String[] configLocations = getConfigLocations(); if (configLocations != null ) { reader.loadBeanDefinitions(configLocations); } }
我们接着追溯 loadBeanDefinitions 方法,会发现由 AbstractBeanDefinitionReader 调用了该方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 public int loadBeanDefinitions (String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException { ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null ) { throw new BeanDefinitionStoreException ( "Cannot load bean definitions from location [" + location + "]: no ResourceLoader available" ); } if (resourceLoader instanceof ResourcePatternResolver) { try { Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int count = loadBeanDefinitions(resources); if (actualResources != null ) { Collections.addAll(actualResources, resources); } if (logger.isTraceEnabled()) { logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]" ); } return count; } catch (IOException ex) { throw new BeanDefinitionStoreException ( "Could not resolve bean definition resource pattern [" + location + "]" , ex); } } else { Resource resource = resourceLoader.getResource(location); int count = loadBeanDefinitions(resource); if (actualResources != null ) { actualResources.add(resource); } if (logger.isTraceEnabled()) { logger.trace("Loaded " + count + " bean definitions from location [" + location + "]" ); } return count; } } public int loadBeanDefinitions (Resource... resources) throws BeanDefinitionStoreException { Assert.notNull(resources, "Resource array must not be null" ); int count = 0 ; for (Resource resource : resources) { count += loadBeanDefinitions(resource); } return count; }
在该方法中,如果 ResourceLoader 同样实现了 ResourcePatternResolver 接口,那么就通过模式匹配的方式加载资源;否则就单纯的使用绝对路径来加载单个资源。至此,所有的资源都已经完成了定位,接下来开始调用 loadBeanDefinitions 方法进行 BeanDefinition 的载入和解析。
BeanDefinition 的载入和解析 在这一过程中,首先需要读取所有定位好的资源,接着要按照一定的规则将读取到的内容转换成 IoC 容器内部的数据结构,这个数据结构对应的就是 BeanDefinition 接口。
我们接着分析上面的代码,在 loadBeanDefinitions 方法中,循环调用了一个同名的 loadBeanDefinitions 方法,该方法只有一个 Resource 参数,由 AbstractBeanDefinitionReader 的子类来实现,在我们的这个例子当中,显然这里调用的是 XmlBeanDefinitionReader 的实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 public int loadBeanDefinitions (Resource resource) throws BeanDefinitionStoreException { return loadBeanDefinitions(new EncodedResource (resource)); } public int loadBeanDefinitions (EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null" ); if (logger.isTraceEnabled()) { logger.trace("Loading XML bean definitions from " + encodedResource); } Set<EncodedResource> currentResources = this .resourcesCurrentlyBeingLoaded.get(); if (currentResources == null ) { currentResources = new HashSet <>(4 ); this .resourcesCurrentlyBeingLoaded.set(currentResources); } if (!currentResources.add(encodedResource)) { throw new BeanDefinitionStoreException ( "Detected cyclic loading of " + encodedResource + " - check your import definitions!" ); } try { InputStream inputStream = encodedResource.getResource().getInputStream(); try { InputSource inputSource = new InputSource (inputStream); if (encodedResource.getEncoding() != null ) { inputSource.setEncoding(encodedResource.getEncoding()); } return doLoadBeanDefinitions(inputSource, encodedResource.getResource()); } finally { inputStream.close(); } } catch (IOException ex) { throw new BeanDefinitionStoreException ( "IOException parsing XML document from " + encodedResource.getResource(), ex); } finally { currentResources.remove(encodedResource); if (currentResources.isEmpty()) { this .resourcesCurrentlyBeingLoaded.remove(); } } } protected int doLoadBeanDefinitions (InputSource inputSource, Resource resource) throws BeanDefinitionStoreException { try { Document doc = doLoadDocument(inputSource, resource); int count = registerBeanDefinitions(doc, resource); if (logger.isDebugEnabled()) { logger.debug("Loaded " + count + " bean definitions from " + resource); } return count; } catch (BeanDefinitionStoreException ex) { throw ex; } }
真正执行载入 Bean 定义的是 doLoadBeanDefinitions 方法。在该方法中,doLoadDocument 方法只负责读取 xml 文档内容,生成一个 Document 对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 protected Document doLoadDocument (InputSource inputSource, Resource resource) throws Exception { return this .documentLoader.loadDocument(inputSource, getEntityResolver(), this .errorHandler, getValidationModeForResource(resource), isNamespaceAware()); } protected int getValidationModeForResource (Resource resource) { int validationModeToUse = getValidationMode(); if (validationModeToUse != VALIDATION_AUTO) { return validationModeToUse; } int detectedMode = detectValidationMode(resource); if (detectedMode != VALIDATION_AUTO) { return detectedMode; } return VALIDATION_XSD; } protected int detectValidationMode (Resource resource) { if (resource.isOpen()) { } InputStream inputStream; try { inputStream = resource.getInputStream(); } catch (IOException ex) { } try { return this .validationModeDetector.detectValidationMode(inputStream); } catch (IOException ex) { throw new BeanDefinitionStoreException ("Unable to determine validation mode for [" + resource + "]: an error occurred whilst reading from the InputStream." , ex); } }
在 doLoadDocument 方法中,我们可以关注一下 getValidationModeForResource 这个方法,该方法主要用来获取应该采用何种方式校验 XML 文件。如果 XML 文件头部包含 DOCTYPE
等关键字,那么会通过 DTD 约束来校验文件;否则会通过 XSD 约束来校验文件。使用了 DTD 约束的 XML 配置文件类似下面这样:
1 2 3 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd" > <beans > </beans >
与此同时,还有一个方法值得关注,那就是 getEntityResolver,该方法用来获取 EntityResolver。我们知道,配置文件在头部会定义约束文件,而约束文件一般都带有 URL 地址,这意味着我们需要网络来获取约束文件,但现实环境往往比较复杂,项目有时会面临离线的状态。为了解决这个问题,约束文件一般会跟随框架一起打包,那么这些约束文件被放在哪里了呢?在 Spring 中,它们的位置被记录在了 META-INF/spring.schemas
文件中。比如我们打开 spring-beans.jar 下的该文件:
1 2 3 4 http\://www.springframework.org/schema/beans/spring-beans-2.0.xsd=org/springframework/beans/factory/xml/spring-beans.xsd http\://www.springframework.org/schema/beans/spring-beans-2.5.xsd=org/springframework/beans/factory/xml/spring-beans.xsd http\://www.springframework.org/schema/beans/spring-beans-3.0.xsd=org/springframework/beans/factory/xml/spring-beans.xsd # 以下省略
可以看到,各个版本以及没有版本号的约束文件,都指向了同一路径下的一个约束文件。在 EntityResolver 接口中,只有一个 resolveEntity 方法,这个方法的作用就是根据提供的约束文件 URL,寻找对应的离线约束文件。
我们接着回到 doLoadBeanDefinitions 方法。此时我们已经将所有的配置转换成了一个 org.w3c.dom.Document
结构,接下来只需要将它转换成对应的 BeanDefinitions 就可以了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public int registerBeanDefinitions (Document doc, Resource resource) throws BeanDefinitionStoreException { BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); int countBefore = getRegistry().getBeanDefinitionCount(); documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); return getRegistry().getBeanDefinitionCount() - countBefore; } public XmlReaderContext createReaderContext (Resource resource) { return new XmlReaderContext (resource, this .problemReporter, this .eventListener, this .sourceExtractor, this , getNamespaceHandlerResolver()); }
在 registerBeanDefinitions 方法中,又创建了一个 BeanDefinitionDocumentReader,然后将文档解析的工作委派给了它,同时还给它额外传入了一个 ReaderContext 参数,这个参数我们可以理解为一个文档读取的上下文环境。在这个上下文环境当中,有一个重要的属性:NamespaceHandlerResolver,乍一看这个名字起的有点奇怪,Handler 后面为什么还加了个 Resolver?我们带着这个问题,查看 getNamespaceHandlerResolver 方法,发现在这里最终是创建了一个默认的实现:DefaultNamespaceHandlerResolver,它的作用是从 META-INF/spring.handlers
文件中加载不同命名空间所对应的 NamespaceHandler。比如 spring-context.jar 下该文件的内容是这样的:
1 2 3 4 5 http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler http\://www.springframework.org/schema/task=org.springframework.scheduling.config.TaskNamespaceHandler http\://www.springframework.org/schema/cache=org.springframework.cache.config.CacheNamespaceHandler
在这里我们随便打开一个 NamespaceHandler,比如 ContextNamespaceHandler:
1 2 3 4 5 6 7 8 9 10 11 12 13 public class ContextNamespaceHandler extends NamespaceHandlerSupport { @Override public void init () { registerBeanDefinitionParser("property-placeholder" , new PropertyPlaceholderBeanDefinitionParser ()); registerBeanDefinitionParser("property-override" , new PropertyOverrideBeanDefinitionParser ()); registerBeanDefinitionParser("annotation-config" , new AnnotationConfigBeanDefinitionParser ()); registerBeanDefinitionParser("component-scan" , new ComponentScanBeanDefinitionParser ()); registerBeanDefinitionParser("load-time-weaver" , new LoadTimeWeaverBeanDefinitionParser ()); registerBeanDefinitionParser("spring-configured" , new SpringConfiguredBeanDefinitionParser ()); registerBeanDefinitionParser("mbean-export" , new MBeanExportBeanDefinitionParser ()); registerBeanDefinitionParser("mbean-server" , new MBeanServerBeanDefinitionParser ()); } }
可以看到,这里初始化的是 context 命名空间中所有可用的元素(标签)和它们对应的解析器,这个解析器被 Spring 抽象为 BeanDefinitionParser 接口。我们常见的一些命名空间配置,比如 <context:component-scan base-package="xxx" />
等,就由这些解析器来处理。
我们回到之前的代码。由于文档解析的工作交给了 BeanDefinitionDocumentReader,同时在这里使用的是它的一个默认实现:DefaultBeanDefinitionDocumentReader,因此我们继续深入到它的方法中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public void registerBeanDefinitions (Document doc, XmlReaderContext readerContext) { this .readerContext = readerContext; doRegisterBeanDefinitions(doc.getDocumentElement()); } protected void doRegisterBeanDefinitions (Element root) { BeanDefinitionParserDelegate parent = this .delegate; this .delegate = createDelegate(getReaderContext(), root, parent); if (this .delegate.isDefaultNamespace(root)) { String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE); if (StringUtils.hasText(profileSpec)) { String[] specifiedProfiles = StringUtils.tokenizeToStringArray( profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS); if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) { if (logger.isDebugEnabled()) { logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + getReaderContext().getResource()); } return ; } } } preProcessXml(root); parseBeanDefinitions(root, this .delegate); postProcessXml(root); this .delegate = parent; }
在该方法中,首先执行了一些前置工作,比如检查默认激活的 profile 与当前解析的文档是否一致,如果不一致则直接跳过解析过程。然后还有两个可以由子类扩展的前置和后置处理的方法,以及真正执行解析工作的 parseBeanDefinitions 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 protected void parseBeanDefinitions (Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root)) { NodeList nl = root.getChildNodes(); for (int i = 0 ; i < nl.getLength(); i++) { Node node = nl.item(i); if (node instanceof Element) { Element ele = (Element) node; if (delegate.isDefaultNamespace(ele)) { parseDefaultElement(ele, delegate); } else { delegate.parseCustomElement(ele); } } } } else { delegate.parseCustomElement(root); } } private void parseDefaultElement (Element ele, BeanDefinitionParserDelegate delegate) { if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) { importBeanDefinitionResource(ele); } else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) { processAliasRegistration(ele); } else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) { processBeanDefinition(ele, delegate); } else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) { doRegisterBeanDefinitions(ele); } } public BeanDefinition parseCustomElement (Element ele) { return parseCustomElement(ele, null ); } public BeanDefinition parseCustomElement (Element ele, @Nullable BeanDefinition containingBd) { String namespaceUri = getNamespaceURI(ele); if (namespaceUri == null ) { return null ; } NamespaceHandler handler = this .readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler == null ) { error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]" , ele); return null ; } return handler.parse(ele, new ParserContext (this .readerContext, this , containingBd)); }
parseBeanDefinitions 方法的逻辑很清晰:根据不同的命名空间,调用不同的处理逻辑。在默认命名空间中有四类标签:import
、alias
、bean
和 beans
,其中 bean
标签对应的处理逻辑能够将 bean 定义转换成 BeanDefinition。对于其他命名空间的标签,我们在前面提到过,使用 NamespaceHandlerResolver 可以获取对应的命名空间处理器,然后将解析工作交给对应的 NamespaceHandler 来处理。这里我们只重点关注 bean
标签的处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 protected void processBeanDefinition (Element ele, BeanDefinitionParserDelegate delegate) { BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null ) { bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); } catch (BeanDefinitionStoreException ex) { getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'" , ele, ex); } getReaderContext().fireComponentRegistered(new BeanComponentDefinition (bdHolder)); } }
在该方法中,parseBeanDefinitionElement 方法将解析 bean
标签并生成对应的 BeanDefinition(创建的是一个 GenericBeanDefinition),最后将它放入一个 BeanDefinitionHolder 中。接下来的需要做的就是将 BeanDefinition 注册到容器中。
BeanDefinition 的注册 向 IoC 容器注册 BeanDefinition 是通过调用 BeanDefinitionRegistry 接口的实现来完成的。简单来说就是在 IoC 容器内部有一个名为 beanDefinitionMap 的 ConcurrentHashMap,注册的过程就是将 BeanDefinition 放入这个 Map 中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public static void registerBeanDefinition ( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); String[] aliases = definitionHolder.getAliases(); if (aliases != null ) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
循环依赖的问题 这部分内容之所以放在容器的依赖注入之前,是因为将这类问题单独拎出来,再结合 Spring 对于循环依赖问题的处理完整分析一遍,对于接下来解析 Spring 依赖注入部分的代码很有帮助。
所谓循环依赖,说白了就是一个或多个对象实例之间存在直接或者间接的依赖关系,这个依赖关系最终形成了一个环形的结构。一般循环依赖可以简化为三种情况,即自己依赖自己,两两之间的直接依赖和多个对象之间的间接依赖。前两种情况的直接循环依赖比较好识别,第三种间接循环依赖的情况有时候因为业务代码调用层级很深,不容易识别出来。
在 Spring 中,出现循环依赖的场景主要有以下几种:
在这些可能出现循环依赖的场景中,有些 Spring 是能够处理的,有些则不能。Spring 跟我们一样,我们在平常编码时无法解决的循环依赖问题,它同样也无法解决,比如多例的 setter 注入和构造器注入。我们举个例子,用大白话来分析一下。假设有两个类 A 和 B,它们之间互相依赖:
1 2 3 4 5 6 7 8 9 public class A { private B b; } public class B { private A a; }
如果我们要实现多例,也就是每次都要创建一个新的对象。在使用 setter 方法注入时,我们首先需要实例化 A,由于 A 依赖于 B,所以我们又实例化了一个 B,然后使用 setter 方法将 B 的实例注入到 A 的实例中。接着我们又发现 B 依赖于 A,同时由于我们要实现多例,那么此时还需要再重新实例化一个 A,然后将这个 A 的新实例通过 setter 注入给 B 的实例。这还没完,A 的新实例也需要注入呀,因此我们又实例化了一个 B 的新实例,如此往复。这显然是没有尽头的,也是无法处理的。
而在构造器注入的场景下,无法解决循环依赖的问题是因为创建对象需要调用构造器,而构造器需要传入依赖的对象,由于此时被依赖的对象还没有创建,因此同样使用构造器创建,不过该构造器也需要传入依赖的对象,这就陷入了死胡同。
DependsOn 循环依赖则比较特殊,它是 Spring 框架特有的。对于一个 Bean,Spring 大体上向用户提供了两种方式来配置它的依赖。一种是使用 depends-on
属性或者 @DependsOn
注解,另一种是使用 ref
属性等类似的方式。其中,通过 ref
属性来配置依赖的对象中需要持有被依赖的对象,而 DependsOn 则不需要。所以我们可以理解为这种依赖只是一种初始化顺序上的依赖,那么因此我们就很容易理解:具有初始化顺序依赖的两个对象之间不应该存在逻辑上(初始化上)的依赖。
到了单例环境中,循环依赖的问题其实是很容易处理的,利用我们经常使用的 setter 方法执行注入即可。
1 2 3 4 A a = new A ();B b = new B ();a.setB(b); b.setA(a);
如果让我们按照这个思路,实现一个简易的,能够处理循环依赖的 IoC 容器,我们应该怎么做呢?回看上面的代码,你会发现其实这是一种延迟初始化的思想。也就说,我们在初始化 Bean 的时候,首先通过无参构造创建了一个“空”对象,接着我们要将这个对象的引用存储起来,方便我们后续还能找到这个未初始化完成的对象,执行 setter 注入。这里有一个很重要的信息,那就是存储对象的引用,因此我们需要一个缓存容器。到了这里,我们离 Spring 的实现又近了一步。没错,Spring 的设计思路跟我们一样,不过不同的是,它一次性使用了三个这样的缓存容器,也就是我们俗称的三级缓存。
1 2 3 4 5 6 7 8 9 10 11 12 private final Map<String, Object> singletonObjects = new ConcurrentHashMap <>(256 );private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap <>(16 );private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap <>(16 );
一级缓存为 singletonObjects,存储的是已经完全初始化的 bean 实例。二级缓存为 earlySingletonObjects,存储的是已经实例化,但是还没有初始化的 bean 实例。三级缓存为 singletonFactories,存储的是能够生成 bean 实例的工厂对象。Spring 为什么要使用三级缓存来处理循环依赖的问题呢?换句话说,只使用一级缓存,或者只使用二级缓存可以吗?答案是不行。
我们先看只使用一级缓存为什么不行。同样还是拿着 A 和 B 这两个类来举例。用户获取 A 的实例,此时缓存容器中没有,因此 A 要先实例化,实例化之后放入缓存容器中,接着我们需要填充 A 的属性,也就是 B 的实例。此时我们需要先从缓存容器中尝试获取 B 的实例,如果没有我们需要先实例化 B。等等!我们先别急着向下分析,在 A 实例化并放入缓存容器之后,如果此时有个用户尝试获取 A 的实例怎么办?或者尝试获取 B 的实例,同样经过了上述步骤,在填充属性时,从缓存容器中拿到了 A 的实例。在这些场景中,A 的实例都没有完全初始化,但是用户已经获取到并开始准备使用它了。这显然是有问题的,而产生问题的关键是我们无法得知某一时刻缓存容器中的实例是否完全初始化了。比较简单直接的解决方法就是使用两个缓存容器,一个存放实例化但没初始化的 bean,另一个存放实例化并且完全初始化的 bean,各司其职。那为什么我们在一开始又说:在 Spring 中,只使用二级缓存是不行的呢?
我们不要忘了,Spring Framework 作为一个成熟的商业产品,IoC 只是它的一个基本功能。除了 IoC,它还有一个很重要也是很基础的功能:AOP。如果一个 bean 经过了 AOP 的织入(Weaving),那么我们拿到的这个 bean 实际上是一个代理 bean。在我们像上面那样去使用二级缓存时,二级缓存中存放只是原始的 bean 实例,这样其他依赖该 bean 的实例在填充属性时获取到的也只是原始的 bean 实例,并不是我们真正想要获取的代理 bean 实例。那么你可能又会问了,如果我们不像上面那样将实例化后的 bean 对象放入二级缓存,而是将代理对象(代理对象包裹着未初始化的原始实例)放入二级缓存中不就行了吗。理论上来说,这是完全没有问题的,那么 Spring 又为什么非要使用三级缓存呢?其实,Spring 的根本目的是为了保证在没有循环依赖的情况下,在引入了 AOP 之后,Bean 的生命周期设计不会得到破坏,即代理对象应该在 bean 初始化完成之后才生成,而不应该在 bean 实例化之后就生成。
我们还是用上面存在循环依赖的 A 和 B 来举例,我们假设只使用二级缓存,并且二级缓存存放的是代理对象,那么整个流程大概就像下图这样:
显然不管有没有循环依赖,在使用二级缓存时,代理对象总是在 bean 完全初始化之前生成。为了解决这个问题,Spring 又设计了一个 ObjectFactory 接口,这个接口是一个函数式接口,只有一个 getObject 方法用来获取实例对象。接下来我们只要在 bean 实例化之后,将它传入一个 ObjectFactory 的实现中,在这个实现中完成 AOP 的织入,最后将这个 ObjectFactory 放入缓存中即可。这样只有在其他依赖此 bean 的实例执行属性填充时,才会从三级缓存中拿到对应的 ObjectFactory,然后通过 getObject 方法创建对应的代理对象。但是,如果每个依赖此 bean 的实例都需要通过 getObject 方法来持有一个代理对象,那么显然它们持有的并不是同一个代理对象。因此我们需要再添加一个缓存容器,然后将 ObjectFactory 存放在三级缓存中,在其他实例获取三级缓存时,将直接调用获取到的 ObjectFactory 的 getObject 方法,并将结果存入二级缓存,同时删除对应的三级缓存,这样下次就可以直接从二级缓存获取代理对象了。
这就是 Spring 三级缓存的由来。在使用了三级缓存之后,如果不存在循环依赖,那么代理对象的创建会在 bean 完全初始化之后才会进行;如果存在循环依赖,整个流程大概就变成下图这样了:
在 Spring 中,AOP 的功能通过 Bean 后置处理器来完成的,更确切的说,是由 @EnableAspectJAutoProxy
注解导入的 AnnotationAwareAspectJAutoProxyCreator
来完成的。在它的 postProcessAfterInitialization 方法中,同样实现了根据已有 bean 实例创建代理对象的逻辑,这也是为什么说如果不存在循环依赖,那么代理对象的创建会在 bean 完全初始化之后才会进行的原因。
IoC 容器的依赖注入 IoC 容器的依赖注入过程是在用户第一次向容器索要 Bean 时触发的,当然也有例外,那些设置 Bean 的 lazy-init 属性为 false(默认就是 false)的 BeanDefinition 会在容器初始化时就完成预实例化。这个预实例化实际上也是一个完成依赖注入的过程,只不过它是在容器初始化的过程中完成的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 public Object getBean (String name) throws BeansException { assertBeanFactoryActive(); return getBeanFactory().getBean(name); } public Object getBean (String name) throws BeansException { return doGetBean(name, null , null , false ); } protected <T> T doGetBean ( String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly) throws BeansException { String beanName = transformedBeanName(name); Object bean; Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null ) { if (logger.isTraceEnabled()) { if (isSingletonCurrentlyInCreation(beanName)) { } else { logger.trace("Returning cached instance of singleton bean '" + beanName + "'" ); } } bean = getObjectForBeanInstance(sharedInstance, name, beanName, null ); } else { if (isPrototypeCurrentlyInCreation(beanName)) { throw new BeanCurrentlyInCreationException (beanName); } BeanFactory parentBeanFactory = getParentBeanFactory(); if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { String nameToLookup = originalBeanName(name); if (parentBeanFactory instanceof AbstractBeanFactory) { return ((AbstractBeanFactory) parentBeanFactory).doGetBean( nameToLookup, requiredType, args, typeCheckOnly); } else if (args != null ) { return (T) parentBeanFactory.getBean(nameToLookup, args); } else if (requiredType != null ) { return parentBeanFactory.getBean(nameToLookup, requiredType); } else { return (T) parentBeanFactory.getBean(nameToLookup); } } if (!typeCheckOnly) { markBeanAsCreated(beanName); } try { RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); checkMergedBeanDefinition(mbd, beanName, args); String[] dependsOn = mbd.getDependsOn(); if (dependsOn != null ) { for (String dep : dependsOn) { if (isDependent(beanName, dep)) { throw new BeanCreationException (mbd.getResourceDescription(), beanName, "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'" ); } registerDependentBean(dep, beanName); try { getBean(dep); } catch (NoSuchBeanDefinitionException ex) { throw new BeanCreationException (mbd.getResourceDescription(), beanName, "'" + beanName + "' depends on missing bean '" + dep + "'" , ex); } } } if (mbd.isSingleton()) { sharedInstance = getSingleton(beanName, () -> { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } }); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); } else if (mbd.isPrototype()) { Object prototypeInstance = null ; try { beforePrototypeCreation(beanName); prototypeInstance = createBean(beanName, mbd, args); } finally { afterPrototypeCreation(beanName); } bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); } else { } } catch (BeansException ex) { cleanupAfterBeanCreationFailure(beanName); throw ex; } } if (requiredType != null && !requiredType.isInstance(bean)) { try { T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); if (convertedBean == null ) { throw new BeanNotOfRequiredTypeException (name, requiredType, bean.getClass()); } return convertedBean; } catch (TypeMismatchException ex) { if (logger.isTraceEnabled()) { logger.trace("Failed to convert bean '" + name + "' to required type '" + ClassUtils.getQualifiedName(requiredType) + "'" , ex); } throw new BeanNotOfRequiredTypeException (name, requiredType, bean.getClass()); } } return (T) bean; }
获取 Bean 的方法最终调用的是 doGetBean 方法。在该方法中,首先尝试从三个级别的缓存中获取单例 bean。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public Object getSingleton (String beanName) { return getSingleton(beanName, true ); } protected Object getSingleton (String beanName, boolean allowEarlyReference) { Object singletonObject = this .singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { singletonObject = this .earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { synchronized (this .singletonObjects) { singletonObject = this .singletonObjects.get(beanName); if (singletonObject == null ) { singletonObject = this .earlySingletonObjects.get(beanName); if (singletonObject == null ) { ObjectFactory<?> singletonFactory = this .singletonFactories.get(beanName); if (singletonFactory != null ) { singletonObject = singletonFactory.getObject(); this .earlySingletonObjects.put(beanName, singletonObject); this .singletonFactories.remove(beanName); } } } } } } return singletonObject; }
如果缓存为空,那么会有三种可能:实例在父容器中,从未创建和初始化过该 bean,这是一个原型 bean。所以接下来会在父容器存在,并且当前容器中没有对应的 BeanDefinition 时,尝试从父容器获取 bean 的实例。如果父容器不存在,或者当前容器中存在对应的 BeanDefinition 时,继续向下执行获取 bean 的过程。
在这个过程中,如果 BeanDefinition 存在继承关系,那么还需要使用 getMergedLocalBeanDefinition 方法合并它们。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 protected RootBeanDefinition getMergedLocalBeanDefinition (String beanName) throws BeansException { RootBeanDefinition mbd = this .mergedBeanDefinitions.get(beanName); if (mbd != null ) { return mbd; } return getMergedBeanDefinition(beanName, getBeanDefinition(beanName)); } protected RootBeanDefinition getMergedBeanDefinition (String beanName, BeanDefinition bd) throws BeanDefinitionStoreException { return getMergedBeanDefinition(beanName, bd, null ); } protected RootBeanDefinition getMergedBeanDefinition ( String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd) throws BeanDefinitionStoreException { synchronized (this .mergedBeanDefinitions) { RootBeanDefinition mbd = null ; if (containingBd == null ) { mbd = this .mergedBeanDefinitions.get(beanName); } if (mbd == null ) { if (bd.getParentName() == null ) { if (bd instanceof RootBeanDefinition) { mbd = ((RootBeanDefinition) bd).cloneBeanDefinition(); } else { mbd = new RootBeanDefinition (bd); } } else { BeanDefinition pbd; try { String parentBeanName = transformedBeanName(bd.getParentName()); if (!beanName.equals(parentBeanName)) { pbd = getMergedBeanDefinition(parentBeanName); } else { BeanFactory parent = getParentBeanFactory(); if (parent instanceof ConfigurableBeanFactory) { pbd = ((ConfigurableBeanFactory) parent).getMergedBeanDefinition(parentBeanName); } else { throw new NoSuchBeanDefinitionException (parentBeanName, "Parent name '" + parentBeanName + "' is equal to bean name '" + beanName + "': cannot be resolved without a ConfigurableBeanFactory parent" ); } } } catch (NoSuchBeanDefinitionException ex) { throw new BeanDefinitionStoreException (bd.getResourceDescription(), beanName, "Could not resolve parent bean definition '" + bd.getParentName() + "'" , ex); } mbd = new RootBeanDefinition (pbd); mbd.overrideFrom(bd); } if (!StringUtils.hasLength(mbd.getScope())) { mbd.setScope(SCOPE_SINGLETON); } if (containingBd != null && !containingBd.isSingleton() && mbd.isSingleton()) { mbd.setScope(containingBd.getScope()); } if (containingBd == null && isCacheBeanMetadata()) { this .mergedBeanDefinitions.put(beanName, mbd); } } return mbd; } }
接着还要处理 BeanDefinition 的 dependsOn 属性,这个依赖可以理解为只有 dependsOn 属性中指定的 bean 先完成初始化之后,该 bean 才能进行初始化。这就意味着,该 bean 并不需要持有依赖对象,如果持有的话直接使用 ref 即可。在这些前期工作完成以后,接下来会通过 getSingleton(beanName, singletonFactory)
方法来获取 bean 的实例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 public Object getSingleton (String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "Bean name must not be null" ); synchronized (this .singletonObjects) { Object singletonObject = this .singletonObjects.get(beanName); if (singletonObject == null ) { if (this .singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException (beanName, "Singleton bean creation not allowed while singletons of this factory are in destruction " + "(Do not request a bean from a BeanFactory in a destroy method implementation!)" ); } if (logger.isDebugEnabled()) { logger.debug("Creating shared instance of singleton bean '" + beanName + "'" ); } beforeSingletonCreation(beanName); boolean newSingleton = false ; boolean recordSuppressedExceptions = (this .suppressedExceptions == null ); if (recordSuppressedExceptions) { this .suppressedExceptions = new LinkedHashSet <>(); } try { singletonObject = singletonFactory.getObject(); newSingleton = true ; } catch (IllegalStateException ex) { singletonObject = this .singletonObjects.get(beanName); if (singletonObject == null ) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this .suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this .suppressedExceptions = null ; } afterSingletonCreation(beanName); } if (newSingleton) { addSingleton(beanName, singletonObject); } } return singletonObject; } }
在该方法中,我们可以看到主要的一行代码就是调用 ObjectFactory 的 getObject 方法,这个方法实际上调用的是 createBean 方法来创建并初始化一个 bean 的实例。由于这个实例是一个完成依赖注入之后的实例,因此最后还会将它放入一级缓存中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 protected Object createBean (String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { RootBeanDefinition mbdToUse = mbd; Class<?> resolvedClass = resolveBeanClass(mbd, beanName); if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null ) { mbdToUse = new RootBeanDefinition (mbd); mbdToUse.setBeanClass(resolvedClass); } try { mbdToUse.prepareMethodOverrides(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException (mbdToUse.getResourceDescription(), beanName, "Validation of method overrides failed" , ex); } try { Object bean = resolveBeforeInstantiation(beanName, mbdToUse); if (bean != null ) { return bean; } } catch (Throwable ex) { throw new BeanCreationException (mbdToUse.getResourceDescription(), beanName, "BeanPostProcessor before instantiation of bean failed" , ex); } try { Object beanInstance = doCreateBean(beanName, mbdToUse, args); if (logger.isTraceEnabled()) { logger.trace("Finished creating instance of bean '" + beanName + "'" ); } return beanInstance; } catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) { throw ex; } catch (Throwable ex) { throw new BeanCreationException ( mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation" , ex); } }
在 createBean 方法中,首先会检查需要创建 bean 实例的类是否可以被实例化。如果容器配置了 BeanPostProcessor,那么在实例化 bean 之前还会调用 Bean 后置处理器的 postProcessBeforeInstantiation 方法完成一些用户自定义的操作。该方法返回的 bean 对象可以是代替目标 bean 的代理对象,这样目标 bean 就不会执行默认的实例化操作,唯一会执行的进一步处理就是调用 Bean 后置处理器的 postProcessAfterInitialization 方法来完成 bean 的初始化操作,然后直接返回初始化完成的 bean。在方法的最后,doCreateBean 才是真正创建并初始化 bean 实例的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 protected Object doCreateBean (String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { BeanWrapper instanceWrapper = null ; if (mbd.isSingleton()) { instanceWrapper = this .factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null ) { instanceWrapper = createBeanInstance(beanName, mbd, args); } Object bean = instanceWrapper.getWrappedInstance(); Class<?> beanType = instanceWrapper.getWrappedClass(); if (beanType != NullBean.class) { mbd.resolvedTargetType = beanType; } synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { try { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); } catch (Throwable ex) { throw new BeanCreationException (mbd.getResourceDescription(), beanName, "Post-processing of merged bean definition failed" , ex); } mbd.postProcessed = true ; } } boolean earlySingletonExposure = (mbd.isSingleton() && this .allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isTraceEnabled()) { logger.trace("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references" ); } addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } Object exposedObject = bean; try { populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); } catch (Throwable ex) { } if (earlySingletonExposure) { Object earlySingletonReference = getSingleton(beanName, false ); if (earlySingletonReference != null ) { if (exposedObject == bean) { exposedObject = earlySingletonReference; } else if (!this .allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) { String[] dependentBeans = getDependentBeans(beanName); Set<String> actualDependentBeans = new LinkedHashSet <>(dependentBeans.length); for (String dependentBean : dependentBeans) { if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) { actualDependentBeans.add(dependentBean); } } if (!actualDependentBeans.isEmpty()) { throw new BeanCurrentlyInCreationException (beanName, "Bean with name '" + beanName + "' has been injected into other beans [" + StringUtils.collectionToCommaDelimitedString(actualDependentBeans) + "] in its raw version as part of a circular reference, but has eventually been " + "wrapped. This means that said other beans do not use the final version of the " + "bean. This is often the result of over-eager type matching - consider using " + "'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example." ); } } } } try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException ( mbd.getResourceDescription(), beanName, "Invalid destruction signature" , ex); } return exposedObject; }
在 doCreateBean 方法中,通过 createBeanInstance 方法来创建 bean 的实例。如果 Spring 容器允许单例 bean 出现循环依赖,那么这个未初始化的 bean 实例会被放入三级缓存中。接下来通过 populateBean 方法对 bean 实例执行属性值的依赖注入,然后使用 initializeBean 方法执行一些初始化的操作。最后通过 registerDisposableBeanIfNecessary 方法注册一些销毁 bean 的回调方法,比如一些 DestructionAwareBeanPostProcessor 接口,DisposableBean 接口,以及自定义的 destroy-method
方法。将未初始化的 bean 实例放入三级缓存这部分代码最简单,我们先来看它。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); protected void addSingletonFactory (String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(singletonFactory, "Singleton factory must not be null" ); synchronized (this .singletonObjects) { if (!this .singletonObjects.containsKey(beanName)) { this .singletonFactories.put(beanName, singletonFactory); this .earlySingletonObjects.remove(beanName); this .registeredSingletons.add(beanName); } } } protected Object getEarlyBeanReference (String beanName, RootBeanDefinition mbd, Object bean) { Object exposedObject = bean; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof SmartInstantiationAwareBeanPostProcessor) { SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp; exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName); } } } return exposedObject; }
其实我想说的是 getEarlyBeanReference 方法,这个方法在容器没有配置 BeanPostProcessor 时只会返回之前未完成初始化的 bean 实例,而如果容器设置了这类 Bean 后置处理器,这里就会调用它们的 getEarlyBeanReference 方法来获得用户特殊处理过的 bean 实例。这个扩展点很多时候是被用来返回经过 AOP 处理的代理 bean 对象。
我们回到刚才的 doCreateBean 方法,继续查看 createBeanInstance 部分的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 protected BeanWrapper createBeanInstance (String beanName, RootBeanDefinition mbd, @Nullable Object[] args) { Class<?> beanClass = resolveBeanClass(mbd, beanName); if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) { throw new BeanCreationException (mbd.getResourceDescription(), beanName, "Bean class isn't public, and non-public access not allowed: " + beanClass.getName()); } Supplier<?> instanceSupplier = mbd.getInstanceSupplier(); if (instanceSupplier != null ) { return obtainFromSupplier(instanceSupplier, beanName); } if (mbd.getFactoryMethodName() != null ) { return instantiateUsingFactoryMethod(beanName, mbd, args); } boolean resolved = false ; boolean autowireNecessary = false ; if (args == null ) { synchronized (mbd.constructorArgumentLock) { if (mbd.resolvedConstructorOrFactoryMethod != null ) { resolved = true ; autowireNecessary = mbd.constructorArgumentsResolved; } } } if (resolved) { if (autowireNecessary) { return autowireConstructor(beanName, mbd, null , null ); } else { return instantiateBean(beanName, mbd); } } Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName); if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR || mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) { return autowireConstructor(beanName, mbd, ctors, args); } ctors = mbd.getPreferredConstructors(); if (ctors != null ) { return autowireConstructor(beanName, mbd, ctors, null ); } return instantiateBean(beanName, mbd); }
在 createBeanInstance 方法中,大体上有四种实例化 bean 的方式。obtainFromSupplier 方法会从 BeanDefinition 中获取一个名为 instanceSupplier 的 Supplier,然后通过这个 Supplier 获取 bean 的实例。instantiateUsingFactoryMethod 使用 FactoryBean 的工厂方法来创建 bean 的实例,需要注意的是该工厂方法可以是一个静态方法。autowireConstructor 方法则是通过构造方法完成 bean 的实例化,不过由于构造函数和构造参数的不确定性,这个方法在没有提供候选的构造函数时需要花大量的精力来确定构造函数和构造参数(可以通过 BeanPostProcessor 提供候选构造器)。最后的 instantiateBean 方法则是使用默认构造函数进行实例化。
我们回到上面的 doCreateBean 方法,继续查看 populateBean 部分的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 protected void populateBean (String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) { if (bw == null ) { if (mbd.hasPropertyValues()) { throw new BeanCreationException ( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance" ); } else { return ; } } if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { return ; } } } } PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null ); int resolvedAutowireMode = mbd.getResolvedAutowireMode(); if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues (pvs); if (resolvedAutowireMode == AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; } boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); PropertyDescriptor[] filteredPds = null ; if (hasInstAwareBpps) { if (pvs == null ) { pvs = mbd.getPropertyValues(); } for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null ) { if (filteredPds == null ) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvsToUse == null ) { return ; } } pvs = pvsToUse; } } } if (needsDepCheck) { if (filteredPds == null ) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } checkDependencies(beanName, mbd, filteredPds, pvs); } if (pvs != null ) { applyPropertyValues(beanName, mbd, bw, pvs); } }
在该方法中,如果容器配置了 Bean 后置处理器,那么就会执行它们的 postProcessAfterInstantiation 方法来完成用户自定义的一些 bean 实例化后的操作。如果 BeanDefinition 配置了自动注入的模式,那么还会选择对应的模式对该 bean 的属性值执行注入。接下来还会执行 Bean 后置处理器的 postProcessProperties 方法,在 bean 注入属性值之前,对属性值进行一些自定义的处理。最终会调用 applyPropertyValues 方法,对 bean 的属性值执行注入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 protected void applyPropertyValues (String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) { if (pvs.isEmpty()) { return ; } if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) { ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext()); } MutablePropertyValues mpvs = null ; List<PropertyValue> original; if (pvs instanceof MutablePropertyValues) { mpvs = (MutablePropertyValues) pvs; if (mpvs.isConverted()) { try { bw.setPropertyValues(mpvs); return ; } catch (BeansException ex) { throw new BeanCreationException ( mbd.getResourceDescription(), beanName, "Error setting property values" , ex); } } original = mpvs.getPropertyValueList(); } else { original = Arrays.asList(pvs.getPropertyValues()); } TypeConverter converter = getCustomTypeConverter(); if (converter == null ) { converter = bw; } BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver (this , beanName, mbd, converter); List<PropertyValue> deepCopy = new ArrayList <>(original.size()); boolean resolveNecessary = false ; for (PropertyValue pv : original) { if (pv.isConverted()) { deepCopy.add(pv); } else { String propertyName = pv.getName(); Object originalValue = pv.getValue(); Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); Object convertedValue = resolvedValue; boolean convertible = bw.isWritableProperty(propertyName) && !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName); if (convertible) { convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter); } if (resolvedValue == originalValue) { if (convertible) { pv.setConvertedValue(convertedValue); } deepCopy.add(pv); } else if (convertible && originalValue instanceof TypedStringValue && !((TypedStringValue) originalValue).isDynamic() && !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) { pv.setConvertedValue(convertedValue); deepCopy.add(pv); } else { resolveNecessary = true ; deepCopy.add(new PropertyValue (pv, convertedValue)); } } } if (mpvs != null && !resolveNecessary) { mpvs.setConverted(); } try { bw.setPropertyValues(new MutablePropertyValues (deepCopy)); } catch (BeansException ex) { throw new BeanCreationException ( mbd.getResourceDescription(), beanName, "Error setting property values" , ex); } }
在该方法中,主要工作是对属性值进行处理,这项工作由 BeanDefinitionValueResolver 的 resolveValueIfNecessary 方法完成。为此还创建了一个属性值的深拷贝列表,所有已经处理过的属性值都会被放入该列表中。当所有的属性值都处理完毕之后,使用 BeanWrapper 的 setPropertyValues 方法,将这个深拷贝列表传入,执行属性值注入的过程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 public Object resolveValueIfNecessary (Object argName, @Nullable Object value) { if (value instanceof RuntimeBeanReference) { RuntimeBeanReference ref = (RuntimeBeanReference) value; return resolveReference(argName, ref); } else if (value instanceof NullBean) { return null ; } else { return evaluate(value); } } private Object resolveReference (Object argName, RuntimeBeanReference ref) { try { Object bean; String refName = ref.getBeanName(); refName = String.valueOf(doEvaluate(refName)); if (ref.isToParent()) { if (this .beanFactory.getParentBeanFactory() == null ) { throw new BeanCreationException ( this .beanDefinition.getResourceDescription(), this .beanName, "Can't resolve reference to bean '" + refName + "' in parent factory: no parent factory available" ); } bean = this .beanFactory.getParentBeanFactory().getBean(refName); } else { bean = this .beanFactory.getBean(refName); this .beanFactory.registerDependentBean(refName, this .beanName); } if (bean instanceof NullBean) { bean = null ; } return bean; } catch (BeansException ex) { } }
我们回到上面的 doCreateBean 方法,继续查看 initializeBean 部分的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 protected Object initializeBean (String beanName, Object bean, @Nullable RootBeanDefinition mbd) { if (System.getSecurityManager() != null ) { AccessController.doPrivileged((PrivilegedAction<Object>) () -> { invokeAwareMethods(beanName, bean); return null ; }, getAccessControlContext()); } else { invokeAwareMethods(beanName, bean); } Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable ex) { throw new BeanCreationException ( (mbd != null ? mbd.getResourceDescription() : null ), beanName, "Invocation of init method failed" , ex); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
在该方法中,invokeAwareMethods 方法用来向 Aware 类型的接口注入它们需要的参数,比如 beanName、beanFactory 等。如果容器配置了 Bean 后置处理器,那么还会调用它们的 postProcessBeforeInitialization 方法,在 bean 完全初始化之前执行一些用户自定义的操作。如果当前 bean 是一个 InitializingBean
,那么还会调用它的 afterPropertiesSet 方法完成一些自定义的配置验证和最终初始化工作。接下来会调用 bean 的 init-method
方法。当然,最终还会调用 Bean 后置处理器的 postProcessAfterInitialization 方法来,在 bean 完全初始化之后完成一些用户自定义的操作。
经过上面的分析,我们已经了解了 doCreateBean 方法的细节,接下来我们回到 doGetBean 方法,来看看 Spring 是如何处理最终返回给用户的 bean 实例的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 protected Object getObjectForBeanInstance ( Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) { if (BeanFactoryUtils.isFactoryDereference(name)) { if (beanInstance instanceof NullBean) { return beanInstance; } if (!(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException (beanName, beanInstance.getClass()); } } if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } Object object = null ; if (mbd == null ) { object = getCachedObjectForFactoryBean(beanName); } if (object == null ) { FactoryBean<?> factory = (FactoryBean<?>) beanInstance; if (mbd == null && containsBeanDefinition(beanName)) { mbd = getMergedLocalBeanDefinition(beanName); } boolean synthetic = (mbd != null && mbd.isSynthetic()); object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; } protected Object getObjectFromFactoryBean (FactoryBean<?> factory, String beanName, boolean shouldPostProcess) { if (factory.isSingleton() && containsSingleton(beanName)) { synchronized (getSingletonMutex()) { Object object = this .factoryBeanObjectCache.get(beanName); if (object == null ) { object = doGetObjectFromFactoryBean(factory, beanName); Object alreadyThere = this .factoryBeanObjectCache.get(beanName); if (alreadyThere != null ) { object = alreadyThere; } else { if (shouldPostProcess) { if (isSingletonCurrentlyInCreation(beanName)) { return object; } beforeSingletonCreation(beanName); try { object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException (beanName, "Post-processing of FactoryBean's singleton object failed" , ex); } finally { afterSingletonCreation(beanName); } } if (containsSingleton(beanName)) { this .factoryBeanObjectCache.put(beanName, object); } } } return object; } } else { Object object = doGetObjectFromFactoryBean(factory, beanName); if (shouldPostProcess) { try { object = postProcessObjectFromFactoryBean(object, beanName); } catch (Throwable ex) { throw new BeanCreationException (beanName, "Post-processing of FactoryBean's object failed" , ex); } } return object; } }
简单说来,如果用户想要获取的 bean 是一个 FactoryBean,那么根据用户传入的 bean 名称(首字符是否为 &
),选择返回 FactoryBean 对象还是返回通过调用它的 getObject 方法返回的对象。而如果用户想要获取的 bean 就是一个普通的 bean,那么直接返回。
Spring Bean 生命周期 在 Spring Bean 的生命周期中,框架为我们提供了一系列扩展方法方便我们调用,可以将这些方法大体分为:bean 级别和容器级别。
bean 级别的方法包括 bean 本身的方法,比如通过配置文件定义的 init-method
方法和 destroy-method
方法,以及 bean 实现的 InitializingBean
、BeanNameAware
、BeanFactoryAware
、DisposableBean
等接口的方法。
容器级别的包括 bean 后置处理器 BeanPostProcessor
和 InstantiationAwareBeanPostProcessor
接口的方法,以及 bean 工厂后置处理器 BeanFactoryPostProcessor
接口的方法等。
如下表格列出的是 Spring Bean 的一般生命周期以及生命周期中的扩展方法,按照从上到下的顺序依次进行。需要注意两个单词:Instantiation
和 Initialization
,它们分别对应了 Bean 的两个生命周期阶段:实例化阶段和初始化阶段。
方法或过程
描述
BeanFactoryPostProcessor.postProcessorBeanFactory
可以对 bean 的定义(配置元数据)进行处理
InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
在 bean 实例化之前执行一些操作
构造器方法
调用 bean 的构造器进行实例化
InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation
在 bean 实例化之后执行一些操作
InstantiationAwareBeanPostProcessor.postProcessPropertyValues
完成其他定制依赖注入和依赖检查等
属性值注入
BeanNameAware.setBeanName
设置 beanName
BeanFactoryAware.setBeanFactory
设置 BeanFactory
ApplicationContextAware.setApplicationContext
设置 ApplicationContext
BeanPostProcessor.postProcessBeforeInitialization
在 bean 初始化之前执行一些操作
InitializingBean.afterPropertiesSet
执行一些初始化操作
init-method 属性指定的方法
执行一些初始化操作
BeanPostProcessor.postProcessAfterInitialization
在 bean 初始化之后执行一些操作
DisposableBean.destroy
在 Bean 销毁之前,执行一些销毁操作
destroy-method 属性指定的方法
在 Bean 销毁之前,执行一些销毁操作
除了上述方法,还有一些方法也可以影响 Bean 生命周期中执行的操作。比如 @PostConstruct
和 @PreDestroy
注解,它们是 JSR 250 规范中定义的注解,Spring 也支持这些注解。被 @PostConstruct
注解标注的方法会在当前 Bean 完成依赖注入之后调用;被 @PreDestroy
注解标注的方法会在当前 Bean 销毁之前调用。
参考
《Spring 技术内幕:深入解析 Spring 架构与计原理 (第 2 版)》