文章目录
最近学习了SpringIOC的源码。将自己的学习成果总结如下。
SpringIOC
IOC容器:所有上层框架bean实例依赖环境
BeanFactory简介
BeanFactory : bean工厂提供bean的实例
beanFactory在早期设计中就只是一个提供bean实例对象工厂,通过各种条件定位到我们所需要的Bean,作为顶层接口定义了IOC容器的基本规范。
我们可以看一下BeanFactory这个接口中声明的属性及方法
-
String FACTORY_BEAN_PREFIX = “&”;
这是BeanFactory接口中的唯一一个属性。这个地方需要衍生出一个概念,Spring 中有两种类型的bean。一种是普通的JavaBean,另一种是工厂bean(FactoryBean,需要实现Spring定义的FactoryBean接口),这两种bean都由SpringIOC容器来进行管理。FactoryBean和javaBean不同的地方在于通过BeanFactory类的getBean方法直接获取到的并不是FactoryBean的实例而是 FactoryBean中的方法getObject返回的对象。假如我们需要获取FactoryBean的实例。我们需要在getBean方法获取实例的时候在参数前加入"&"符号就行了。即BeanFactory中的FACTORY_BEAN_PREFIX属性。
-
Object getBean(String name) throws BeansException;
通过名称获取bean实例,之后会详细讲解这个方法
-
T getBean(String name, Class requiredType) throws BeansException;
通过注释 Behaves the same as {@link #getBean(String)}, but provides a measure of type 我们可以看出来这个方法行为和getBean(String name)相同,但是提供了类型的度量。不同于上面的getBean方法的是。如果我们获取到的bean和传入的类型不一致,则会抛出BeanNotOfRequiredTypeException异常。
-
T getBean(Class requiredType) throws BeansException;
返回与所需类型匹配的单个bean的实例
-
Object getBean(String name, Object… args) throws BeansException;
args参数,用于使用显式参数创建bean实例
*(仅在创建新实例而不是检索现有实例时应用) -
T getBean(Class requiredType, Object… args) throws BeansException;
同理获取给定类型的bean,args参数在创建实例时使用
-
boolean containsBean(String name);
是否包含该bean
-
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
这个bean是否是单例
-
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
是否getBean方法每次都返回不同的实例
-
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
检查具有给定名称的bean是否与指定类型匹配。这里插一点内容。ResolvableType是Spring4.0之后推出的一个类。不同于下面这个方法的是。Class是一种类型,但它本身不具有类型的属性。ResolvableType为所有的java类型提供了统一的数据结构以及API,换句话说,一个ResolvableType对象就对应着一种java类型。我们可以通过ResolvableType对象获取类型携带的信息。例如父类型,接口类型,Type对象到class对象的转换等。在Spring框架中需要反射的时候,为了不丢失信息,通常使用ResolvableType来进行封装类型。
-
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
检查具有给定名称的bean是否与指定类型匹配。
-
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
获取具有给定名称的bean的类型。
-
String[] getAliases(String name);
返回别名,如果没有则返回空数组。在getBean方法中,所有的别名都指向同一个Bean。如果传入的参数是别名,则同时返回原始Bean的名称,并且Bean的名称作为数组中的第一个元素。
逐步演进发展成这样:
我们再分别分析BeanFactory的子接口。
ListableBeanFactory
这个接口声明了一些获取多个Bean的方法。在BeanFactory中,getBean方法获取的都是单个Bean。大致看一下ListableBeanFactory中声明的方法
通过方法名我们可以很清晰的看到每个方法的作用,这里引入了一个新的名称:BeanDefinition。
BeanDefinition
BeanDefinition接口继承了AttributeAccessor,BeanMetadataElement接口。
AttributeAccessor接口定义了最基本的对任意对象的元数据的修改或者获取。基本接口如下:
BeanMetadataElement 接口提供了一个getResource()方法,用来传输一个可配置的源对象。getResource方法返回此元数据元素的配置源对象。
看完两个接口以后,我们再来看BeanDefinition的声明
一个BeanDefinition描述了一个bean的实例,包括属性值,构造方法参数值和继承自它的类的更多信息。BeanDefinition仅仅是一个最简单的接口,主要功能是允许BeanFactoryPostProcessor例如PropertyPlaceHolderConfigure能够检索并修改属性值和别的bean的元数据。BeanDefinition就是Spring中的Bean,我们定义的Bean会转化成为一个个BeanDefinition存在于Spring的BeanFactory当中。注意几个比较重要的点:
-
setAutowireCandidate方法
设置该bean是否可以注入到其他的Bean当中。只对根据类型注入有效。如果根据名称注入,即使这里设置的为false。也可以注入成功。
-
setPrimary 方法
当同一个接口有多个实现的时候,Spring会优先选择设置primary为true的bean
-
BeanFactoryPostProcessor
对已经加载好的BeanDefinition进行处理。SpringIOC容许BeanFactoryPostProcessor在容器实际实例化任何bean之前读取配置的元数据。例如我们常用的${property}这样的表达式,实际上就是对配置信息进行替换。这样使得配置解耦。具体的实现逻辑就是在BeanFactoryPostProcessor相关的实现类中的postProcessBeanFactory方法中实现的。
-
methodOverrides
方法重写的持有者,记录lookup-method,replaced-method元素。
HierarchicalBeanFactory
接下来继续看HierarchicalBeanFactory接口,实现该接口的BeanFactory具有继承关系。
AutowireCapableBeanFactory接口,实现该接口的BeanFactory可以自动装配bean。
BeanFactory的默认实现类DefaultListableBeanFactory。随着Spring的扩展,DefaultListableBeanFactory无法满足各种各样的情况下Bean的获取及生产。然后又逐步演进出了ApllicationContext。SpringIOC的过程中,本质上是ApplicationContext持有了一个DefaultListableBeanFactory。这个类很重要,他同时实现了BeanDefinitionRegistry接口。BeanDefinitionRegistry接口的主要作用是向注册表中注册BeanDefinition实例。完成注册的过程。
DefaultListableBeanFactory
DefaultListableBeanFactory是BeanFactory的默认实现类,实现了BeanFactory下层的三个接口。
ApllicationContext
ApllicationContext的架构图如下所示:
IOC容器初始化过程
资源加载 -> 资源解析 -> BeanDefinition注册 -> getBean()获取bean的实例
ContextLoaderListener
传统的Spring项目中,我们需要在web.xml文件中配置如下内容:
org.springframework.web.context.ContextLoaderListenerContextLoaderListener 继承自ContextLoader,实现了ServletContextListener接口。
这里是可以看作是我们Spring在web开发过程中的起点,ContextLoaderListener可以指定在web应用程序启动时载入IOC容器,正是通过ContextLoader来实现的。ContextLoader来完成实际的WebApplicationContext也就是IOC容器的初始化工作。ServletContextListener接口里的函数会结合Web容器的生命周期被调用。因为ServletContextListener是ServletContext的监听者,如果ServletContext发生变化,会触发相应的事件,而监听器一直对事件监听,如果接受到了变化,就会做出预先设计好的相应动作,由于ServletContext变化而触发的监听器的响应有服务器启动时,servletContext被创建,服务器关闭时,servletContext被销毁。所以contextLoaderListener的作用是启动web容器时,读取在contextConfigLocation中定义的xml文件,自动装配ApplicationContext的配置信息,并产生WebApplicationContext对象。然后将这个对象放置在ServletContext的属性里。这样我们可以通过servlet获取到WebApplicationContext对象,并利用这个对象访问Spring容器管理的bean。
同样我们还需要在web.xml中配置context-param参数。
contextConfigLocation /WEB-INF/ * -servlet.xml,classpath:conf/applicationContext- * .xml在ContextLoader的加载过程中,会读取contextConfigLocation参数的值,然后解析资源配置文件。
代码调用链
接下来我们启动一个Spring配置的项目,来一步一步的解析IOC容器的初始化过程。
contextInitialized
首先代码的入口在ContextLoaderListener的contextInitialized方法中,ServletContext创建时会调用该方法。
@Override
public void contextInitialized(ServletContextEvent event) {
initWebApplicationContext(event.getServletContext());
}
我们可以看到这个方法实际上是调用了contextLoader类里面的initWebApplicationContext方法。接下来我们点进initWebApplicationContext方法中。
initWebApplicationContext
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!");
}
Log logger = LogFactory.getLog(ContextLoader.class);
servletContext.log("Initializing Spring root WebApplicationContext");
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();
try {
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
if (this.context == null) {
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
if (!cwac.isActive()) {
// The context has not yet been refreshed -> provide services such as
// setting the parent context, setting the application context id, etc
if (cwac.getParent() == null) {
// The context instance was injected without an explicit parent ->
// determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, this.context);
}
if (logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}
return this.context;
}
catch (RuntimeException ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
catch (Error err) {
logger.error("Context initialization failed", err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
throw err;
}
}
这个方法里面有几个比较重要的方法。首先在ServletContext中找有没有ApplicationContext存在,如果有则报错,因为ServletContext只会初始化一次,ApplicationContext也只会创建一次。接下来我们看createWebApplication(servlet)方法
createWebApplication
在createWebApplication方法中,首先通过datermineContextClass(sc)来确定实现类,如果在web.xml中配置了contextClass参数,值为webApplicationContext的实现类,则返回配置类的Class。如果没有配置,则会返回Spring默认的实现类XmlWebApplicationContext。然后生成一个ApplicationContext的对象。
回到initWebApplicaitonContext方法中,因为XmlWebApplicationContext间接实现了ConfigurableWebApplicationContext接口,所以将会执行configureAndRefreshWebApplicationContext(cwac, servletContext);方法。
configureAndRefreshWebApplicationContext
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
// The application context id is still set to its original default value
// -> assign a more useful id based on available information
String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
if (idParam != null) {
wac.setId(idParam);
}
else {
// Generate default id...
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(sc.getContextPath()));
}
}
wac.setServletContext(sc);
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) {
wac.setConfigLocation(configLocationParam);
}
// The wac environment's #initPropertySources will be called in any case when the context
// is refreshed; do it eagerly here to ensure servlet property sources are in place for
// use in any post-processing or initialization that occurs below prior to #refresh
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
customizeContext(sc, wac);
wac.refresh();
}
这个方法我们可以看到会读取我们前面配置在web.xml文件当中的contextConfigLocation参数,如果没有配置,默认读取路径为 “/WEB-INF/applicationContext.xml”。这个方法里面有一个最重要的方法,refresh();这个方法才是真正的Spring配置工作,具体实现在AbstractApplicationContext当中。接下来会具体讲这个方法。
refresh
这个方法是SpringIOC容器初始化的核心,需要一个一个的讲解,先大概看一下具有以下的方法。
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 初始化准备工作
prepareRefresh();
// 获取BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// BeanFactory的预准备工作
prepareBeanFactory(beanFactory);
try {
// beanFactory准备工作完成之后进行的后置处理工作。
postProcessBeanFactory(beanFactory);
// 调用BeanFactoryPostProcessor各个实现类的postProcessFactory(factory)方法。
invokeBeanFactoryPostProcessors(beanFactory);
// 注册BeanPostProcessor的实现类
registerBeanPostProcessors(beanFactory);
// 初始化当前ApplicationContext的MessageSource
initMessageSource();
//初始化ApplicationContext事件广播器
initApplicationEventMulticaster();
// 钩子方法,在这里可以初始化一些特殊的bean
onRefresh();
// 注册事件监听器
registerListeners();
// 初始化所有的singleton beans
finishBeanFactoryInitialization(beanFactory);
//广播初始化完成
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
prepareRefresh
准备工作,记录下容器的启动时间,标记为已启动状态,处理配置文件中的占位符。
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}
// Initialize any placeholder property sources in the context environment
initPropertySources();
// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
obtainFreshBeanFactory
将配置文件解析为bean的定义,注册到BeanFactory中。bean还没有完全初始化,但是具有了一个beanName->beanDefinition的map
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
refreshBeanFactory
实现类位于AbstractRefreshableApplicationContext
@Override
protected final void refreshBeanFactory() throws BeansException {
//如果ApplicationContext中已经加载过了BeanFactory,销毁所有的Bean并关闭BeanFactory。
//这里需要知道,应用中的BeanFactory可以是多个的,检查的是当前ApplicationContext是否有BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 初始化一个DefaultListableBeanFactory。
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 将BeanFactory进行序列话
beanFactory.setSerializationId(getId());
// 设置BeanFactory的两个属性,是否允许Bean覆盖,是否允许循环引用。
customizeBeanFactory(beanFactory);
// 加载Bean到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);
}
}
通过观察hasBeanFactory方法我们可以知道,这里检查的是当前对象的属性beanFactory是否被初始化了。所以ApplicationContext继承自BeanFactory,但本质上是持有了一个DefaultListableBeanFactory的对象。
-
customizeBeanFactory
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) { // 是否允许Bean的定义覆盖 if (this.allowBeanDefinitionOverriding != null) { beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } // 是否允许Bean循环依赖 if (this.allowCircularReferences != null) { beanFactory.setAllowCircularReferences(this.allowCircularReferences); } }
默认情况下,Spring允许循环依赖。之后会讲解Spring如何解决循环依赖的问题。
-
loadBeanDefinitions
实现类在XmlWebApplicationContext中
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setEnvironment(this.getEnvironment()); beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); 这一步构造了一个XmlBeanDefinitionReader实例。我们可以看到的是传入了一个BeanDefinitionRegistry的实现对象beanFactory。在之后的解析过程中,我们所使用的registry就是用的beanFactory。
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException { String[] configLocations = getConfigLocations(); if (configLocations != null) { for (String configLocation : configLocations) { reader.loadBeanDefinitions(configLocation); } } }
这个地方的configLocations实质上就是我们前面在web.xml里面配置的contextConfigLocation参数。
接下来我们来看reader.loadBeanDefinitions(configLocation);这个方法。这个方法的实现位于XmlBeanDefinitionReader的父类AbstractBeanDefinitionReader中。经过简单的调用之后,执行以下代码:
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException { //之前新建对象时会初始化一个ResourceLoader,这里返回ResourceLoader。 ResourceLoader resourceLoader = getResourceLoader(); if (resourceLoader == null) { throw new BeanDefinitionStoreException( "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available"); } if (resourceLoader instanceof ResourcePatternResolver) { // Resource pattern matching available. try { //获取资源,这里返回的就是一个我们配置的xml文件的资源。 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location); int loadCount = loadBeanDefinitions(resources); if (actualResources != null) { for (Resource resource : resources) { actualResources.add(resource); } } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]"); } return loadCount; } catch (IOException ex) { throw new BeanDefinitionStoreException( "Could not resolve bean definition resource pattern [" + location + "]", ex); } } else { // Can only load single resources by absolute URL. Resource resource = resourceLoader.getResource(location); int loadCount = loadBeanDefinitions(resource); if (actualResources != null) { actualResources.add(resource); } if (logger.isDebugEnabled()) { logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]"); } return loadCount; } }
我们来看这一步int loadCount = loadBeanDefinitions(resources); 这里经过简单的调用之后会进入XmlBeanDefinitionReader的loadBeanDefinitions方法。如下:
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException { Assert.notNull(encodedResource, "EncodedResource must not be null"); if (logger.isInfoEnabled()) { logger.info("Loading XML bean definitions from " + encodedResource.getResource()); } //这里获取资源,第一次进来的时候为null Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get(); if (currentResources == null) { //初始化并赋值给resourcesCurrentlyBeingLoaded currentResources = new HashSet<EncodedResource>(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(); } } }
这个方法就是简单的获取文件流然后调用doLoadBeanDefinitions方法。接下来我们来看一下doLoadBeanDefinitions方法。这个方法依旧在XmlBeanDefinitionReader中
主要只有两行代码
// 将资源文件解析为Document
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
接下来我们看registerBeanDefinitions。
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//使用DefaultBeanDefinitionDocumentReader实例化BeanDefinitionDocumentReader
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 记录统计前BeanDefintion的加载个数
int countBefore = getRegistry().getBeanDefinitionCount();
// 加载及注册bean
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
// 记录本次加载的BeanDefintion个数
return getRegistry().getBeanDefinitionCount() - countBefore;
}
这里调用了documentReader的registerBeanDefinitions方法。实现类为DefaultBeanDefinitionDocumentReader
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
走到这一步的时候,资源文件已经变成了一个Element,接下来就是解析这个Element并注册了。
protected void doRegisterBeanDefinitions(Element root) {
// BeanDefinitionParserDelegate 用于解析XML bean定义的有状态委托类。
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
//这里是解析配置了profile属性的beans
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)) {
return;
}
}
}
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
- BeanDefinitionParserDelegate类提供了解析spring配置文件功能,对于默认空间下的元素()在该类内部实现,对于其它命名空间下的元素可以通过绑定NamespaceHandler的方式来实现,针对每个命名空间下的元素提供不同BeanDefinitionParser来实现.
- preProcessXml和postProcessXml都是空的。钩子方法。一个类要么是面向继承设计,要么就用final修饰。
- 判断是否为默认的命名空间 。即root的namespaceURI是否为http://www.springframework.org/schema/beans
- 假如我们配置了Spring.profiles.active属性,则会对beans标签进行解析,是否是当前环境所需要的bean
- 重点讲解DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法。
parseBeanDefinitions
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);
}
}
这里我们可以看到所有的解析方法都进入了parseDefaultElement(ele, delegate);和 delegate.parseCustomElement(ele);parseDefaultElement方法解析的是,,,
这四个标签之所以是默认标签,是因为他们处于http://www.springframework.org/schema/beans这个namespace下定义的。
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)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
其他的标签类似于,,,等都会进入parseCustomElement这个方法。
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
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));
}
processBeanDefinition
不同的标签会有不同的NamespaceHandler来进行解析。我们看一下bean标签是如何被解析的
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//将<bean/>标签节点的信息提取出来,然后封装到一个BeanDefintionHolder中。包含了配置文件中配置的各种属性了。
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
我们来跟进如何解析BeanDefinition的。首先从元素的解析及信息提取开始。也就是 BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);方法。我们进入BeanDefinitionDelegate类的parseBeanDefinitionElement方法。如下:
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
//解析id属性
String id = ele.getAttribute(ID_ATTRIBUTE);
//解析name属性
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
//分割name属性
List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
//如果没有指定id,则设置别名列表的第一个名字作为beanN啊,e
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
//根据bean标签的配置创建Beandefinition。
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
//如果不存在beanName,则根据Spring中提供的命名规则为当前bean生成对应的beanName
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
这个方法主要做了以下几步
-
提取元素的id和name属性
-
进一步解析其他所有的属性并统一封装到AbstractBeanDefinition类型的实例中
-
如果检测到bean没有制定beanName,那么使用默认规则为此bean生成beanName
-
将获取到的信息封装到BeanDefinitionHolder的实例中。
看一下如何封装到AbstractBeanDefinition当中的。
public AbstractBeanDefinition parseBeanDefinitionElement( Element ele, String beanName, BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null; //解析class属性 if (ele.hasAttribute(CLASS_ATTRIBUTE)) { className = ele.getAttribute(CLASS_ATTRIBUTE).trim(); } try { String parent = null; if (ele.hasAttribute(PARENT_ATTRIBUTE)) { parent = ele.getAttribute(PARENT_ATTRIBUTE); } //创建BeanDefinition并设置类信息。 AbstractBeanDefinition bd = createBeanDefinition(className, parent); //解析bean的各种属性 parseBeanDefinitionAttributes(ele, beanName, containingBean, bd); //设置description bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); //解析<meta/> parseMetaElements(ele, bd); //解析<lookup-method/> parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //解析<replaced-method/> parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //解析<constructor-arg/> parseConstructorArgElements(ele, bd); //解析<property/> parsePropertyElements(ele, bd); //解析<qualifier/> parseQualifierElements(ele, bd); bd.setResource(this.readerContext.getResource()); bd.setSource(extractSource(ele)); return bd; } catch (ClassNotFoundException ex) { error("Bean class [" + className + "] not found", ele, ex); } catch (NoClassDefFoundError err) { error("Class that bean class [" + className + "] depends on not found", ele, err); } catch (Throwable ex) { error("Unexpected failure during bean definition parsing", ele, ex); } finally { this.parseState.pop(); } return null; }
可以看到的是这个方法将标签都解析到AbstractBeanDefinition上了。
- meta标签:meta标签并不会体现在bean的属性当中,而是需要的时候通过BeanDefinition的getAttribute获取。
- lookup-method标签:Spring动态改变bean里方法的实现。方法执行返回的对象,使用Spring内原有的这类对象替换,通过改变方法返回值来动态改变方法,内部实现为使用cglib方法。重新生成子类,重写配置的方法和返回对象,达到动态改变的效果。这段话看起来有点抽象,我们通常称为获取器注入,我们在lookup-method标签里定义的name为方法名,bean为返回值对象。
- replaced-method:方法替换,可以在运行时用新的方法替换现有的方法。与之前的look-up不同的是,replaced-method不但可以动态地替换返回实体bean,而且还能动态地更改原有方法的逻辑。
到这一步,我们已经根据一个bean标签完成了一个BeanDefinitionHolder实例的创建。我们看一下BeanDefinitionHolder里面的内容。
回到processBeanDefinition中,当我们完成processBeanDefintion后我们接下来会进行bean的注册
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.如果还有别名,将别名也注册
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
显而易见,这个方法里面最重要的就是 registry.registerBeanDefinition。结合我们上面的提到的registry就是DefaultListableBeanFactory。接下来我们看DefaultListableBeanFactory的注册方法registerBeanDefinition。
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
//beanDefinitionMap实质上就是DefaultListableBeanFactory持有的一个ConcurrentHashMap
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
//如果不允许覆盖,则抛一场
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
//getRole 获取bean的分类,
///Bean角色,
// int ROLE_APPLICATION = 0; //应用程序重要组成部分
// int ROLE_SUPPORT = 1; //做为大量配置的一部分(支持、扩展类)
// int ROLE_INFRASTRUCTURE = 2; //指内部工作的基础构造
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
//判断是否有bean已经开始初始化了
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase 将beanDefinition放入map当中
this.beanDefinitionMap.put(beanName, beanDefinition);
// 已经注册的beanName添加进去
this.beanDefinitionNames.add(beanName);
// 从需要手动注册的bean中删除
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
到这一步,bean的解析已经完成了。我们回到refresh方法中。
prepareBeanFactory
设置BeanFactory的类加载器,添加几个BeanPostProcessor(还未注册BeanPostProcessor),手动注册特殊的bean。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// Tell the internal bean factory to use the context's class loader etc.
//为ApplicationContext设置类加载器。
beanFactory.setBeanClassLoader(getClassLoader());
//设置BeanExpressionResovler SpEL表达式的解析器
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// Configure the bean factory with context callbacks.
//设置BeanPostProcessor
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 自动装备时忽略以下几个类
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// Detect a LoadTimeWeaver and prepare for weaving, if found.
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// Set a temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
// Register default environment beans.
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}
- 这里又新引入了一个概念BeanPostProcessor。BeanPostProcessor可以在Spring容器实例化bean之后,在执行bean的初始化方法前后,添加一些自己的处理逻辑。bean的初始化方法指的是实现了initializingBean接口的afterPropertiesSet方法。或者bean定义时通过init-methode设置的方法。而BeanFactoryPostProcessor我们在上文中有提到过,在spring容器加载了bean的定义文件之后,在bean实例化之前执行的,允许修改bean的属性,例如将scope从singleton改为prototype。
看完了xml是如何解析的之后,我们直接进入正题,bean是如何实例化及初始化的。我们想要获取一个bean通常通过BeanFactory的getBean方法来获取。finishBeanFactoryInitialization方法通过简单的链式调用之后,也会进入到getBean方法中。getBean调用了doGetBean方法。
doGetBean
protected <T> T doGetBean(
final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
//获取beanName,这里需要注意两个点。一种是处理FactoryBean,一种是将别名转换为真实的beanName。
final String beanName = transformedBeanName(name);
Object bean;
//检查缓存中或者实例工厂中是否有对应的实例。
//因为在创建单例bean的时候会存在依赖注入的情况,而在创建依赖的时候为了避免循环依赖,
//Spring创建bean的原则是不等bean创建完成就会将创建bean的ObjectFactory提早曝光
//也就是将ObjectFactory加入到缓存中,一旦下个bean创建时候需要依赖上个bean则直接使用ObjectFactory
Object sharedInstance = getSingleton(beanName);
// 假如doGetBean方法传入了args参数,那么我们不再是获取bean了,而是重新创建bean
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 这个地方大家看起来可能就会有疑问了,明明已经获取了sharedInstance,为什么还要获取bean。
// 这里其实就是因为如果是普通的bean,那么就直接返回sharedInstance了,
// 如果是FactoryBean,那么我们返回FactoryBean的getObject对象。除非传入了&符号,则返回当前对象等。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
// 假如当前线程已经创建过此beanName的原型的bean。那么会抛异常。这种情况产生的可能性是因为循环依赖。
// 原型模式的情况下,无法解决循环依赖,因为依赖之后会重新创建对象。A创建B,B创建A。
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
//如果beanDefinitionMap中没有这个bean并且父beanFactory存在。则尝试从父容器中获取。
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
//如果不是仅仅做类型检查,而是创建bean,则将当前的beanName传入到一个alreadyCreated的Set集合当中
//进行记录
markBeanAsCreated(beanName);
}
// 到这一步就表明已经需要创建bean了。
try {
// 将存储xml配置文件的GenericBeanDefinition转换为RootBeanDefinition。
// 如果BeanName是子Bean,同时会合并父类的相关属性。
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
//先实例化依赖的所有的bean
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dependsOnBean : dependsOn) {
if (isDependent(beanName, dependsOnBean)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dependsOnBean + "'");
}
// 缓存依赖调用
registerDependentBean(dependsOnBean, beanName);
getBean(dependsOnBean);
}
}
// 实例化所依赖的bean之后就可以实例化mbd本身了。
// 单例模式创建
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
// 创建bean
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
// 这里等同于上面的方法,解决FactoryBean等问题。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
// 如果不是singleton和prototype类型的bean,则需要使用自己指定的scope的委托类来实现初始化。
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type [" +
ClassUtils.getQualifiedName(requiredType) + "]", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
-
FactoryBean#getObject()代理了getBean()方法。
-
getSingleton() 这一步是尝试从缓存中获取单例bean
-
protected Object getSingleton(String beanName, boolean allowEarlyReference) { // singletonObjects concurrentHashMap 存储了BeanName和bean实例之间的关系。 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { // 判断一下是否正在加载,正在加载则不处理。 // earlySingletonObjects也是保存beanName和bean实例之间的关系,但不同的是bean被放入之后 // 即使bean还在创建过程中,就可以通过getBean方法获取了,目的是为了检测循环引用。 singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { // singletonFactories 用来保存beanName和创建bean工厂之间的关系。 // ObjectFactory只是一个普通的工厂接口,不同于FactoryBean。 ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { singletonObject = singletonFactory.getObject(); this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return (singletonObject != NULL_OBJECT ? singletonObject : null); }
-
getObjectForBeanInstance
看完这个方法之后,我们来分析getObjectForBeanInstance;
protected Object getObjectForBeanInstance( Object beanInstance, String name, String beanName, RootBeanDefinition mbd) { // 不属于FactoryBean或者beanName有&前缀 异常 if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) { throw new BeanIsNotAFactoryException(transformedBeanName(name), beanInstance.getClass()); } //现在我们有了bean实例,它可能是一个普通的bean或FactoryBean。 //如果它是FactoryBean,我们将使用它来创建Bean实例, //除非调用者实际上想要对工厂的引用。 if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) { return beanInstance; } Object object = null; if (mbd == null) { // 尝试从缓存中加载bean object = getCachedObjectForFactoryBean(beanName); } if (object == null) { // Return bean instance from factory. // 可以确定Object是FactoryBean,从FactoryBean中获取对象 FactoryBean<?> factory = (FactoryBean<?>) beanInstance; // Caches object obtained from FactoryBean if it is a singleton. if (mbd == null && containsBeanDefinition(beanName)) { // 将存储XML配置文件的GernericBeanDefinition转换为RootBeanDefinition // 如果指定BeanName是子Bean的话同时会合并父类的相关属性。 mbd = getMergedLocalBeanDefinition(beanName); } // 是否是用户定义的bean而不是应用程序本身定义的bean boolean synthetic = (mbd != null && mbd.isSynthetic()); object = getObjectFromFactoryBean(factory, beanName, !synthetic); } return object; }
我们可以看到真正的获取对象方法在getObjectFromFactoryBean中,限于篇幅,我们就不点进去了,但这个方法中主要的代码就是从FactoryBean#getObject()及一些前置后置处理。回到doGetBean当中,我们发现没有实例化的单例对象会调用createBean方法。我们找到一个实现类AbstractAutowireCapableBeanFactory的createBean方法。
- createBean
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
//确保Class被加载
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
// Prepare method overrides.
try {
//。处理<lookup-method>和<replaced-method>标签的方法
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
// 添加BeanPostProcessor的代理
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);
}
// 将持有代理的mbdToUse传入进行bean对象的创建
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
-
doCreateBean
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { //instanceWrapper为null代表不是FactoryBean,则实例化bean instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null); Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null); // Allow post-processors to modify the merged bean definition. synchronized (mbd.postProcessingLock) { if (!mbd.postProcessed) { applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName); mbd.postProcessed = true; } } // 是否需要提前曝光。 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { if (logger.isDebugEnabled()) { logger.debug("Eagerly caching bean '" + beanName + "' to allow for resolving potential circular references"); } //。为了避免后期循环依赖,可以在bean初始化完成前,将创建实例的ObjectFactory加入工厂。 addSingletonFactory(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { return getEarlyBeanReference(beanName, mbd, bean); } }); } // Initialize the bean instance. Object exposedObject = bean; try { // 对bean进行填充,将各个属性赋值。如果有循环依赖则递归初始化依赖bean。 populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { // 调用初始化方法,init-method方法。以及BeanPostProcessor的回调 exposedObject = initializeBean(beanName, exposedObject, mbd); } } catch (Throwable ex) { if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) { throw (BeanCreationException) ex; } else { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", 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<String>(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 " + "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."); } } } } // Register bean as disposable. try { registerDisposableBeanIfNecessary(beanName, bean, mbd); } catch (BeanDefinitionValidationException ex) { throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex); } return exposedObject; }
这个方法中比较重要的三步
- createBeanInstance 实例化bean,将BeanDefinition转化为BeanWrapper。
- populateBean 属性赋值
- initializeBean 毁掉方法
createBeanInstance
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
// 解析class
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());
}
// 如果工厂方法部位空则使用工厂方法初始化策略
if (mbd.getFactoryMethodName() != null) {
return instantiateUsingFactoryMethod(beanName, mbd, args);
}
// Shortcut when re-creating the same bean...
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);
}
}
// 判断是否采用有参构造函数
// Need to determine the constructor...
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
return autowireConstructor(beanName, mbd, ctors, args);
}
//调用无参构造函数
return instantiateBean(beanName, mbd);
}
-
无参构造函数instantiateBean -> getInstantitionStrategy().instantiate()
-
下面我们看一下实例化策略
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) { // Don't override the class with CGLIB if no overrides. // 如果不存在方法覆载,则直接使用反射生成对象 if (bd.getMethodOverrides().isEmpty()) { Constructor<?> constructorToUse; synchronized (bd.constructorArgumentLock) { constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod; if (constructorToUse == null) { final Class<?> clazz = bd.getBeanClass(); if (clazz.isInterface()) { throw new BeanInstantiationException(clazz, "Specified class is an interface"); } try { if (System.getSecurityManager() != null) { constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() { @Override public Constructor<?> run() throws Exception { return clazz.getDeclaredConstructor((Class[]) null); } }); } else { constructorToUse = clazz.getDeclaredConstructor((Class[]) null); } bd.resolvedConstructorOrFactoryMethod = constructorToUse; } catch (Exception ex) { throw new BeanInstantiationException(clazz, "No default constructor found", ex); } } } return BeanUtils.instantiateClass(constructorToUse); } else { //存在方法覆写,则需要使用cglib return instantiateWithMethodInjection(bd, beanName, owner); } }
-
populateBean
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) { PropertyValues pvs = mbd.getPropertyValues(); if (bw == null) { if (!pvs.isEmpty()) { throw new BeanCreationException( mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance"); } else { // Skip property population phase for null instance. return; } } // bean的实例化已经完成,但是还未给属性复制 // InstantiationAwareBeanPostProcessor可以对bean进行状态的修改 boolean continueWithPropertyPopulation = true; if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { continueWithPropertyPopulation = false; break; } } } } if (!continueWithPropertyPopulation) { return; } if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // 根据名称注入属性 // newPvs中存储了一个propertyValueList, // list里面装有属性PropertyValue,含有属性的名称和值等属性 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // 根据类型注入属性 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) { autowireByType(beanName, mbd, bw, newPvs); } pvs = newPvs; } boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE); if (hasInstAwareBpps || needsDepCheck) { PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); if (hasInstAwareBpps) { for (BeanPostProcessor bp : getBeanPostProcessors()) { if (bp instanceof InstantiationAwareBeanPostProcessor) { InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvs == null) { return; } } } } if (needsDepCheck) { checkDependencies(beanName, mbd, filteredPds, pvs); } } // 将属性应用到bean中 applyPropertyValues(beanName, mbd, bw, pvs); }
-
InstantiationAwareBeanPostProcessor接口继承BeanPostProcessor接口,它内部提供了3个方法,再加上BeanPostProcessor接口内部的2个方法,所以实现这个接口需要实现5个方法。
// postProcessBeforeInstantiation方法的作用在目标对象被实例化之前调用的方法,可以返回目标实例的一个代理用来代替目标实例
// beanClass参数表示目标对象的类型,beanName是目标实例在Spring容器中的name
// 返回值类型是Object,如果返回的是非null对象,接下来除了postProcessAfterInitialization方法会被执行以外,其它bean构造的那些方法都不再执行。否则那些过程以及postProcessAfterInitialization方法都会执行
Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;// postProcessAfterInstantiation方法的作用在目标对象被实例化之后并且在属性值被populate之前调用
// bean参数是目标实例(这个时候目标对象已经被实例化但是该实例的属性还没有被设置),beanName是目标实例在Spring容器中的name
// 返回值是boolean类型,如果返回true,目标实例内部的返回值会被populate,否则populate这个过程会被忽视
boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;// postProcessPropertyValues方法的作用在属性中被设置到目标实例之前调用,可以修改属性的设置
// pvs参数表示参数属性值(从BeanDefinition中获取),pds代表参数的描述信息(比如参数名,类型等描述信息),bean参数是目标实例,beanName是目标实例在Spring容器中的name
// 返回值是PropertyValues,可以使用一个全新的PropertyValues代替原先的PropertyValues用来覆盖属性设置或者直接在参数pvs上修改。如果返回值是null,那么会忽略属性设置这个过程(所有属性不论使用什么注解,最后都是null)
PropertyValues postProcessPropertyValues(
PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName)
throws BeansException;InstantiationAwareBeanPostProcessor接口的主要作用在于目标对象的实例化过程中需要处理的事情,包括实例化对象的前后过程以及实例的属性设置
postProcessBeforeInstantiation方法是最先执行的方法,它在目标对象实例化之前调用,该方法的返回值类型是Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有postProcessAfterInitialization方法会调用,其它方法不再调用;否则按照正常的流程走
postProcessAfterInstantiation方法在目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。如果该方法返回false,会忽略属性值的设置;如果返回true,会按照正常流程设置属性值
postProcessPropertyValues方法对属性值进行修改(这个时候属性值还未被设置,但是我们可以修改原本该设置进去的属性值)。如果postProcessAfterInstantiation方法返回false,该方法不会被调用。可以在该方法内对属性值进行修改
父接口BeanPostProcessor的2个方法postProcessBeforeInitialization和postProcessAfterInitialization都是在目标对象被实例化之后,并且属性也被设置之后调用的
Instantiation表示实例化,Initialization表示初始化。实例化的意思在对象还未生成,初始化的意思在对象已经生成
-
到这一步实例化和属性赋值都已经完成了,接下来就进行初始化操作
initializeBean
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
// 如果bean实现了一些Aware接口,则进行回调。
// 实现Aware接口的bean会被注入相应实例。
// 例如我们项目开发过程中常用的ApplicationContextAware接口来获取ApplicationContext
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// BeanPostProcessor的postProcessBeforeInitialization回调
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 调用用户自定义的init方法
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()) {
// BeanPostProcessor的postProcessAfterInitialization回调
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
走到这一步,我们就知道了BeanPostProcessor接口到底在哪里进行回调了。实例化及属性赋值完成之后对初始化的对象进行前后回调了。
总结
限于篇幅,有些地方的代码可能还不够深入,但SpringIOC容器初始化的过程就大致如上所示了。