您的位置:首页 > 编程语言 > Java开发

Spring 3.2 源码解析 -- XML bean 元素到 BeanDefinition 解析过程

2014-05-22 01:29 866 查看
大体过程

XML 的 <bean ...> ---> Document. element ---> GenericBeanDefinition ---> AbstractBeanDefinition implements BeanDefinition ---> BeanDefinitionHolder ----> registory<bean, beanDefinition>

一、 观察者模式

Java 使用观察者模式可以通过下面两个java.util.EventListener 和 java.util.EventoObject 的类和接口实现。

1. Create listeners

package com.colorcc.test.event.listener;

import java.util.EventListener;
import java.util.EventObject;

public interface ColorccListener<E extends EventObject> extends EventListener {

public void onAction(E e);

}


package com.colorcc.test.event.listener;

import com.colorcc.test.event.object.StartEvent;

public class StartListener implements ColorccListener<StartEvent> {

private String name;

public StartListener (String name) {
this.name = name;
}

@Override
public void onAction(StartEvent event) {
System.out.println(name + " ---- start listener ..." + event.getName());
}

}


2. Create event

package com.colorcc.test.event.object;

import java.util.EventObject;

public class StartEvent extends EventObject {

private static final long serialVersionUID = 7312681426368400653L;

public StartEvent(Object source) {
super(source);
}

public String getName() {
return " start event ";
}
}


3. Publish the event

package com.colorcc.test.event.publish;

import java.util.ArrayList;
import java.util.EventObject;
import java.util.List;

import com.colorcc.test.event.listener.StartListener;
import com.colorcc.test.event.object.StartEvent;

public class StartEventPublisher implements EventPublisher {

@Override
public void publishEvent(EventObject event) {
if (event instanceof StartEvent) {
StartEvent startEvent = (StartEvent) event;

for (StartListener startListener : getStartListener(startEvent)) {
startListener.onAction(startEvent);
}
}
}

public static List<StartListener> getStartListener(StartEvent event) {
List<StartListener> linsteners = new ArrayList<StartListener>();
linsteners.add(new StartListener("linstener1"));
linsteners.add(new StartListener("linstener2"));
linsteners.add(new StartListener("linstener3"));
return linsteners;
}

public static void main(String[] args) {
// 创建一个活动
StartEvent event = new StartEvent("start");
// 得到该活动对应所有监听器
for (StartListener startListener : getStartListener(event)) {
// 触发监听器的监听动作
startListener.onAction(event);
}

}
}


Servlet 的 观察者例子如下:

public interface ServletContextListener extends EventListener {
// 通过 web.xml 配置,在 Servlet 容器启动时,调用该接口
public void contextInitialized(ServletContextEvent sce);

public void contextDestroyed(ServletContextEvent sce);
}
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
...
       // Listener 的具体实现,这是 Spring 容器通过 XML 配置方式的直接入口点
// 其中 ServletContextEvent 中包含了一个 ServletContext,为Servlet 容易其境初始化了,传递给 Spring 供后继使用
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
if (this.contextLoader == null) {
this.contextLoader = this;
}
this.contextLoader.initWebApplicationContext(event.getServletContext());
}
....
}
public class ServletContextEvent extends java.util.EventObject {

private static final long serialVersionUID = -7501701636134222423L;

public ServletContextEvent(ServletContext source) {
super(source);
}

public ServletContext getServletContext () {
return (ServletContext) super.getSource();
}
}
public class JettyWebAppContext extends WebAppContext extentd ... implements ServletContext


二、Spring 容器启动的入口点

Spring 容器启动的一种方式为配置 web.xml,加入如下行

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Spring 容器启动的原理如下:

2.1. Servlet (Jetty)容器启动,会读取 web project 的 WEB-INF/web.xml 文件,并使用 web.xml 的相关配置,初始化 ServletContext (JettyWebContext),该 context 包括 web 自身的一些信息。如 Servlet 的版本号,用户 web project 所在的绝对路劲等。例如:

然后当读到 <listener> 元素时,调用 Spring 容器的:

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
...
       // Listener 的具体实现,这是 Spring 容器通过 XML 配置方式的直接入口点
// 其中 ServletContextEvent 中包含了一个 ServletContext,为Servlet 容器初始化了,传递给 Spring 供后继使用
public void contextInitialized(ServletContextEvent event) {
                // 兼容低版本的 Spring
this.contextLoader = createContextLoader();
if (this.contextLoader == null) {
this.contextLoader = this;
}
                // 此处为 Spring 容易初始化的起始位置
this.contextLoader.initWebApplicationContext(event.getServletContext());
}
....
}

注: ContextLoadListener 在加载的时候,会通过其父类的 <cinit> 方法,读取 properties 配置文件,将 XmlWebApplicationContext 作为容器初始化的默认方式。

2.2 其中 initWebApplicationContext 内容如下:

/**
* Initialize Spring's web application context for the given servlet context,
* using the application context provided at construction time, or creating a new one
* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
* "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
* @param servletContext current servlet context
* @return the new WebApplicationContext
* @see #ContextLoader(WebApplicationContext)
* @see #CONTEXT_CLASS_PARAM
* @see #CONFIG_LOCATION_PARAM
*/
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
// 如果 context 已经存在,则抛出异常
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.
// 刚启动,则 content (WebApplicationContext) 为 null,创建一个新的 WebApplicationContext
if (this.context == null) {
// 该处读取 web.xml 的 配置文件 contextClass 属性
//       String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
// 如果存在,则用该属性的 class 初始化容器,否则使用默认 (XmlWebApplicationContext) 初始化容器,
// 最终通过反射方式返回一个 ConfigurableWebApplicationContext (WebApplicationContext)对象

// <?xml version="1.0" encoding="UTF-8"?>
// <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
// 	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" // 	version="3.0">
// 	<display-name>User Register</display-name>
// 	<context-param>
// 		<param-name>webAppRootKey</param-name>
// 		<param-value>register.root</param-value>
// 	</context-param>
//      <context-param>
// 		<param-name>contextClass</param-name>
// 		<param-value>com.colorcc.test.ContextClass</param-value>
// 	</context-param>
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
// 该方法为 Spring 容易启动的逻辑所在
configureAndRefreshWebApplicationContext((ConfigurableWebApplicationContext)this.context, 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;
}
}
Spring 容器启动的业务逻辑
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...
if (sc.getMajorVersion() == 2 && sc.getMinorVersion() < 5) {
// Servlet <= 2.4: resort to name specified in web.xml, if any.
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(sc.getServletContextName()));
}
else {
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(sc.getContextPath()));
}
}
}

// Determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(sc);

wac.setParent(parent);
wac.setServletContext(sc);
// 配置 Spring 容器初始化的 配置文件位置,以后程序会设置默认为 applicationContext.xml
String initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (initParameter != null) {
wac.setConfigLocation(initParameter);
}
// 通过 String classNames = servletContext.getInitParameter("contextInitializerClasses")
// 检查是否有 ApplicationContextInitializer<ConfigurableApplicationContext> <strong>元素</strong>,如果有则
// 继续初始化
customizeContext(sc, wac);

// 核心逻辑:刷新 ApplicationContext
wac.refresh();
}
Spring 核心
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
initMessageSource();

// Initialize event multicaster for this context.
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
onRefresh();

// Check for listener beans and register them.
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
finishRefresh();
}

catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}
}
}

三、 Spring refresh

该方法调用
// Initialize any placeholder property sources in the context environment

initPropertySources();
首先创建 StandardServletEnvironment 对象,该对象实现 ConfigurableWebEnvironment 接口。初始化如下一些属性[servletConfigInitParams,servletContextInitParams,jndiProperties,systemProperties,systemEnvironment] 作为 environment 的 propertySources (MutablePropertySources)属性。
/** Servlet context init parameters property source name: {@value} */
public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";

/** Servlet config init parameters property source name: {@value} */
public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";

/** JNDI property source name: {@value} */
public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";

/** System environment property source name: {@value} */
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
/** JVM system properties property source name: {@value} */
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
其中 servletContextInitParams 的值为 servlet 初始化的 servletContext 值。
servletConfigInitParams 的值为 servlet 初始化的 servletConfig 值 null.
systemProperties = System.getProperties() 值:
{java.runtime.name=Java(TM) SE Runtime Environment, sun.boot.library.path=/opt/dev/jdk/jre/lib/amd64, java.vm.version=20.6-b01, java.vm.vendor=Sun Microsystems Inc., java.vendor.url=http://java.sun.com/, guice.disable.misplaced.annotation.check=true, path.separator=:, java.vm.name=Java HotSpot(TM) 64-Bit Server VM, file.encoding.pkg=sun.io, sun.java.launcher=SUN_STANDARD, user.country=US, sun.os.patch.level=unknown, java.vm.specification.name=Java Virtual Machine Specification, user.dir=/opt/dev/workspace_jack/register-api, java.runtime.version=1.6.0_31-b04, java.awt.graphicsenv=sun.awt.X11GraphicsEnvironment, java.endorsed.dirs=/opt/dev/jdk/jre/lib/endorsed, os.arch=amd64, java.io.tmpdir=/tmp, line.separator=
, java.vm.specification.vendor=Sun Microsystems Inc., os.name=Linux, classworlds.conf=/opt/dev/maven/bin/m2.conf, sun.jnu.encoding=UTF-8, java.library.path=/opt/dev/jdk/jre/lib/amd64/server:/opt/dev/jdk/jre/lib/amd64:/opt/dev/jdk/jre/../lib/amd64:/usr/java/packages/lib/amd64:/usr/lib64:/lib64:/lib:/usr/lib, java.specification.name=Java Platform API Specification, java.class.version=50.0, sun.management.compiler=HotSpot 64-Bit Tiered Compilers, os.version=3.6.10-2.fc16.x86_64, user.home=/home/qtj, user.timezone=PRC, java.awt.printerjob=sun.print.PSPrinterJob, file.encoding=UTF-8, java.specification.version=1.6, java.class.path=/opt/dev/maven/boot/plexus-classworlds-2.4.jar, user.name=qtj, java.vm.specification.version=1.0, sun.java.command=org.codehaus.plexus.classworlds.launcher.Launcher jetty:run, java.home=/opt/dev/jdk/jre, sun.arch.data.model=64, user.language=en, java.specification.vendor=Sun Microsystems Inc., java.vm.info=mixed mode, java.version=1.6.0_31, securerandom.source=file:/dev/./urandom, java.ext.dirs=/opt/dev/jdk/jre/lib/ext:/usr/java/packages/lib/ext, sun.boot.class.path=/opt/dev/jdk/jre/lib/resources.jar:/opt/dev/jdk/jre/lib/rt.jar:/opt/dev/jdk/jre/lib/sunrsasign.jar:/opt/dev/jdk/jre/lib/jsse.jar:/opt/dev/jdk/jre/lib/jce.jar:/opt/dev/jdk/jre/lib/charsets.jar:/opt/dev/jdk/jre/lib/modules/jdk.boot.jar:/opt/dev/jdk/jre/classes, java.vendor=Sun Microsystems Inc., maven.home=/opt/dev/maven, file.separator=/, java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport.cgi, sun.io.unicode.encoding=UnicodeLittle, sun.cpu.endian=little, sun.desktop=gnome, sun.cpu.isalist=}
systemEnvironment = System.getenv() 值:
{TERM=dumb, M3_HOME=/opt/dev/maven, JAVA_HOME=/opt/dev/jdk, IMSETTINGS_MODULE=IBus, KDEDIRS=/usr, SESSION_MANAGER=local/unix:@/tmp/.ICE-unix/1654,unix/unix:/tmp/.ICE-unix/1654, GNOME_DESKTOP_SESSION_ID=this-is-deprecated, IMSETTINGS_INTEGRATE_DESKTOP=yes, MAIL=/var/spool/mail/qtj, MYSQL_HOME=/usr/local/mysql, GDMSESSION=gnome, XDG_SESSION_COOKIE=ffe1f31cb920b0b7dc5fbf9c00000010-1359204139.589544-488163775, PWD=/opt/dev/workspace_jack/register-api, HOSTNAME=tianjie, CVS_RSH=ssh, NLSPATH=/usr/dt/lib/nls/msg/%L/%N.cat, HISTSIZE=1000, PATH=/opt/dev/jdk/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/mysql/bin:/opt/dev/maven/bin:/opt/dev/jvmstat/bin:/opt/dev/mongodb/bin:/home/qtj/.local/bin:/home/qtj/bin, KDE_IS_PRELINKED=1, XAUTHORITY=/var/run/gdm/auth-for-qtj-JeQMx2/database, GDM_LANG=en_US.utf8, XDG_SEAT=seat0, WINDOWPATH=1, XDG_SESSION_ID=2, USERNAME=qtj, XDG_VTNR=1, GNOME_KEYRING_CONTROL=/tmp/keyring-RzXvpG, SHLVL=1, XFILESEARCHPATH=/usr/dt/app-defaults/%L/Dt, JVMSTAT_HOME=/opt/dev/jvmstat, MONGODB_HOME=/opt/dev/mongodb, QT_IM_MODULE=xim, LOGNAME=qtj, GPG_AGENT_INFO=/tmp/keyring-RzXvpG/gpg:0:1, XMODIFIERS=@im=ibus, SSH_AUTH_SOCK=/tmp/keyring-RzXvpG/ssh, LD_LIBRARY_PATH=/opt/dev/jdk/jre/lib/amd64/server:/opt/dev/jdk/jre/lib/amd64:/opt/dev/jdk/jre/../lib/amd64, OLDPWD=/opt/dev/workspace_jack/register-api, DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-k39Bi7yZfr,guid=0c1549cdbe6af23acd2ba61400000040, SHELL=/bin/bash, GNOME_KEYRING_PID=1648, MAVEN_OPTS=-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8083,server=y,suspend=y, CLASSPATH=.:/opt/dev/jdk/lib/dt.jar:/opt/dev/jdk/lib/tools.jar, DESKTOP_SESSION=gnome, DISPLAY=:0.0, USER=qtj, HOME=/home/qtj, HISTCONTROL=ignoredups, LESSOPEN=||/usr/bin/lesspipe.sh %s, XDG_RUNTIME_DIR=/run/user/qtj, LANG=en_US.utf8}


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

该方法调用 初始化一个 DefaultListableBeanFactory对象,该对象提供一堆容器以及一些默认配置,供以后 factory 创建 bean 时装入不同中间变量和最终结果。如:
List<BeanPostProcessor>
Map<String, RootBeanDefinition>
Set<Class> ignoredDependencyInterfaces = new HashSet<Class>();
private boolean allowBeanDefinitionOverriding = true;
private final List<String> beanDefinitionNames = new ArrayList<String>();
private final Map<String, BeanDefinition> = new ConcurrentHashMap<String, BeanDefinition>(64);等。
同时,该 factory 提供ignoreDependencyInterface方法,忽略 Aware 接口的对象。该接口提供一些钩子功能,供用户反向调用 Aware 接口的具体对象。如:
ignoreDependencyInterface(.class);

ignoreDependencyInterface(.class);

ignoreDependencyInterface(.class);
以及设置 parentBeanFactory,对于全局 application 而言, parentBeanFactory 为 null。对于具体的 servlet,其 parentBeanFactory 则为 root 对应的 beanFactory。
该方法还调用 方法:
实现如下功能:
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
beanFactory.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
}
最终调用方法 实现 XML 元素[b]解析[/b]功能。
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
                // 创建 XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
               
                // Configure the bean definition reader with this context's
// resource loading environment.
                // 设置 reader 的一些默认值
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
                // 注意该处设置一个 schema 的默认值
                // public static final String DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas";
                // this.schemaMappingsLocation = DEFAULT_SCHEMA_MAPPINGS_LOCATION;
                // 即读取每个 jar 包的 META-INF/spring.schemas 文件,知道对应的 schema 文件
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);

// 通过该方法<strong><strong>解析</strong></strong> XML 文件
loadBeanDefinitions(beanDefinitionReader);
}

首先该方法通过如下代码查找由 web.xml 中配置的 Spring 全局XML 配置文件文件。
String[] configLocations = getConfigLocations();
由下代码便可知我们 project 中默认的 applicationContext.xml 的由来。 这也是 Spring 的一个常用规则:
到处设置默认值,便于用户使用。
/** Default config location for the root context */
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";

/** Default prefix for building a config location for a namespace */
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";

/** Default suffix for building a config location for a namespace */
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";

protected String[] getDefaultConfigLocations() {
if (getNamespace() != null) {
return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
}
else {
return new String[] {DEFAULT_CONFIG_LOCATION};
}
}
最终调用的一些业务逻辑代码如下:
reader.loadBeanDefinitions(configLocation);
return loadBeanDefinitions(location, null);
Resource[] = ((ResourcePatternResolver) resourceLoader).getResources(location);
----> 其值为
int loadCount = loadBeanDefinitions(resources);

XmlBeanDefinitionReader :
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}

doLoadBeanDefinitions(inputSource, encodedResource.getResource());
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
int validationMode = getValidationModeForResource(resource);
// 通过调用 JAXP <strong><strong>解析</strong></strong> applicationContext.xml 文件为 Document 对象
Document doc = this.documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
return registerBeanDefinitions(doc, resource);
}
...
}
根据 Document 对象,[b]解析[/b]其中每个元素

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {

// private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;
// BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
documentReader.setEnvironment(this.getEnvironment());
int countBefore = getRegistry().getBeanDefinitionCount();
// 该处设置了 spring.handlers 的默认值
// public static final String DEFAULT_HANDLER_MAPPINGS_LOCATION="META-INF/spring.handlers";
// this(classLoader, DEFAULT_HANDLER_MAPPINGS_LOCATION);
// 即读取每个 jar 包中的 META-INF/spring.handlers 文件,<strong><strong>解析</strong></strong>其中的 property 值
// 最终创建的 XmlReaderContext 为:
// XmlReaderContext(Resource resource, ProblemReporter problemReporter,
//       ReaderEventListener eventListener, SourceExtractor sourceExtractor,
//       XmlBeanDefinitionReader reader, NamespaceHandlerResolver namespaceHandlerResolver)
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
其中 registerBeanDefinitions(Document doc, XmlReaderContext readerContext) 的调用逻辑为:
doRegisterBeanDefinitions(Element root)
--> BeanDefinitionParserDelegate parent = this.delegate;

this.delegate = createHelper(readerContext, root, parent);
protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
// 创建 BeanDefinitionParserDelegate 对象
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext, environment);
// 使用父 delegate 和默认值,初始化 delegate 对应的属性值
delegate.initDefaults(root, parentDelegate);
return delegate;
}
通过 BeanDefinitionParserDelegate 代码,我们看到一个XML一个 bean
元素包含的属性如下:
public class BeanDefinitionParserDelegate {

public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";

public static final String MULTI_VALUE_ATTRIBUTE_DELIMITERS = ",; ";

/** @deprecated as of Spring 3.1 in favor of {@link #MULTI_VALUE_ATTRIBUTE_DELIMITERS} */
public static final String BEAN_NAME_DELIMITERS = MULTI_VALUE_ATTRIBUTE_DELIMITERS;

/**
* Value of a T/F attribute that represents true.
* Anything else represents false. Case seNsItive.
*/
public static final String TRUE_VALUE = "true";

public static final String FALSE_VALUE = "false";

public static final String DEFAULT_VALUE = "default";

public static final String DESCRIPTION_ELEMENT = "description";

public static final String AUTOWIRE_NO_VALUE = "no";

public static final String AUTOWIRE_BY_NAME_VALUE = "byName";

public static final String AUTOWIRE_BY_TYPE_VALUE = "byType";

public static final String AUTOWIRE_CONSTRUCTOR_VALUE = "constructor";

public static final String AUTOWIRE_AUTODETECT_VALUE = "autodetect";

public static final String DEPENDENCY_CHECK_ALL_ATTRIBUTE_VALUE = "all";

public static final String DEPENDENCY_CHECK_SIMPLE_ATTRIBUTE_VALUE = "simple";

public static final String DEPENDENCY_CHECK_OBJECTS_ATTRIBUTE_VALUE = "objects";

public static final String NAME_ATTRIBUTE = "name";

public static final String BEAN_ELEMENT = "bean";

public static final String META_ELEMENT = "meta";

public static final String ID_ATTRIBUTE = "id";

public static final String PARENT_ATTRIBUTE = "parent";

public static final String CLASS_ATTRIBUTE = "class";

public static final String ABSTRACT_ATTRIBUTE = "abstract";

public static final String SCOPE_ATTRIBUTE = "scope";

public static final String SINGLETON_ATTRIBUTE = "singleton";

public static final String LAZY_INIT_ATTRIBUTE = "lazy-init";

public static final String AUTOWIRE_ATTRIBUTE = "autowire";

public static final String AUTOWIRE_CANDIDATE_ATTRIBUTE = "autowire-candidate";

public static final String PRIMARY_ATTRIBUTE = "primary";

public static final String DEPENDENCY_CHECK_ATTRIBUTE = "dependency-check";

public static final String DEPENDS_ON_ATTRIBUTE = "depends-on";

public static final String INIT_METHOD_ATTRIBUTE = "init-method";

public static final String DESTROY_METHOD_ATTRIBUTE = "destroy-method";

public static final String FACTORY_METHOD_ATTRIBUTE = "factory-method";

public static final String FACTORY_BEAN_ATTRIBUTE = "factory-bean";

public static final String CONSTRUCTOR_ARG_ELEMENT = "constructor-arg";

public static final String INDEX_ATTRIBUTE = "index";

public static final String TYPE_ATTRIBUTE = "type";

public static final String VALUE_TYPE_ATTRIBUTE = "value-type";

public static final String KEY_TYPE_ATTRIBUTE = "key-type";

public static final String PROPERTY_ELEMENT = "property";

public static final String REF_ATTRIBUTE = "ref";

public static final String VALUE_ATTRIBUTE = "value";

public static final String LOOKUP_METHOD_ELEMENT = "lookup-method";

public static final String REPLACED_METHOD_ELEMENT = "replaced-method";

public static final String REPLACER_ATTRIBUTE = "replacer";

public static final String ARG_TYPE_ELEMENT = "arg-type";

public static final String ARG_TYPE_MATCH_ATTRIBUTE = "match";

public static final String REF_ELEMENT = "ref";

public static final String IDREF_ELEMENT = "idref";

public static final String BEAN_REF_ATTRIBUTE = "bean";

public static final String LOCAL_REF_ATTRIBUTE = "local";

public static final String PARENT_REF_ATTRIBUTE = "parent";

public static final String VALUE_ELEMENT = "value";

public static final String NULL_ELEMENT = "null";

public static final String ARRAY_ELEMENT = "array";

public static final String LIST_ELEMENT = "list";

public static final String SET_ELEMENT = "set";

public static final String MAP_ELEMENT = "map";

public static final String ENTRY_ELEMENT = "entry";

public static final String KEY_ELEMENT = "key";

public static final String KEY_ATTRIBUTE = "key";

public static final String KEY_REF_ATTRIBUTE = "key-ref";

public static final String VALUE_REF_ATTRIBUTE = "value-ref";

public static final String PROPS_ELEMENT = "props";

public static final String PROP_ELEMENT = "prop";

public static final String MERGE_ATTRIBUTE = "merge";

public static final String QUALIFIER_ELEMENT = "qualifier";

public static final String QUALIFIER_ATTRIBUTE_ELEMENT = "attribute";

public static final String DEFAULT_LAZY_INIT_ATTRIBUTE = "default-lazy-init";

public static final String DEFAULT_MERGE_ATTRIBUTE = "default-merge";

public static final String DEFAULT_AUTOWIRE_ATTRIBUTE = "default-autowire";

public static final String DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE = "default-dependency-check";

public static final String DEFAULT_AUTOWIRE_CANDIDATES_ATTRIBUTE = "default-autowire-candidates";

public static final String DEFAULT_INIT_METHOD_ATTRIBUTE = "default-init-method";

public static final String DEFAULT_DESTROY_METHOD_ATTRIBUTE = "default-destroy-method";

private final DocumentDefaultsDefinition defaults = new DocumentDefaultsDefinition();
同时,通过DocumentDefaultsDefinition 我们可以看到 beans 的全局配置属性如下:
public class DocumentDefaultsDefinition implements DefaultsDefinition {

private String lazyInit;

private String merge;

private String autowire;

private String dependencyCheck;

private String autowireCandidates;

private String initMethod;

private String destroyMethod;

private Object source;

现在逻辑为通过 parseBeanDefinitions(root, this.delegate);
[b]解析
[/b] bean 元素:其代码如下:
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);
}
}
其中 DefaultNamespace 为 beans 的默认元素,用 parseDefaultElement(ele, delegate);[b]解析[/b]
DefaultNamespace为beans的非默认元素(如 context, mvc等),用delegate.parseCustomElement(ele);[b]解析[/b]
DefaultNamespace 不为 beans,则通过 delegate.parseCustomElement(root);
[b]解析[/b]
我们先看第一种请客:
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);
}
}
[b]解析[/b] bean 的代码:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 将生成的 beanDefinition 存入 registry 中
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));
}
}
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
--> parseBeanDefinitionElement(ele, null);
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
// 对应<strong><strong>解析</strong></strong>XML文件的 id, name <strong>元素</strong>
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

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;
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) {
// name 需唯一
checkNameUniqueness(beanName, aliases, ele);
}
// <strong><strong>解析</strong></strong> <bean> <strong>元素</strong>的属性值,如 class="...", parent=...
// 此处会为每个 bean 创建一个默认的 GenericBeanDefinition 对象,其有 bean 对象的一些默认值,如:
//  parent, beanClass, attributes, singleton = true; lazyInit = false; 等
// 同时还会<strong><strong>解析</strong></strong> <bean> 里面嵌套的<strong>元素</strong>,如 meta, replaced-method, replaced-method 等
// <strong><strong>解析</strong></strong>的<strong>元素</strong>还包括: constructor-arg, property, qualifier 等。 最终一个例子如:

// Generic bean: class [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in ServletContext resource [/WEB-INF/applicationContext.xml]
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
// 如果 beanName 为空,则通过默认方式,生成一个 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);
// 最终将 beanDefinition, beanName, aliasesArray 赋值给 BeanDefinitionHolder 并返回
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}

return null;
}
代码 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); 逻辑如下:
public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {

BeanDefinitionHolder finalDefinition = definitionHolder;

// Decorate based on custom attributes first.
// <strong><strong>解析</strong></strong> bean 对应的 attribute 属性,如:
// [autowire="default", autowire-candidate="default", class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer", id="propertyConfigurer", lazy-init="default", p:location="WEB-INF/jdbc.properties"]
NamedNodeMap attributes = ele.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
// 如果不是默认命名空间,则会调用下面逻辑先<strong><strong>解析</strong></strong>命名空间:
//    NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
// 在 resolve()里会有如下逻辑从 META-INF/spring.handlers 载入所有 handler:
//    Properties mappings = PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
// 然后通过<strong>元素</strong>所属的空间名,找到对应的 NamespaceHandler, 如: SimplePropertyNamespaceHandler,MvcNamespacehandler
//    通过反射方式方式,实例化对应的 handler,并调用 init() 方法,实现初始化。
// 最终通过 handler 的 decorate 方法转换 XML 对应的 attribute 值为 Bean 对应的 MutablePropertyValues 值,并赋值给 definition.
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}

// Decorate based on custom nested elements.
NodeList children = ele.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
}
return finalDefinition;
}
这样通过如上的操作,得到 bean
元素
对应的 BeanDefinition,验证一定的逻辑之后,将其存入 beanFacotry 相关容器中,供后面程序使用。
this..add(beanName);
this..put(beanName, beanDefinition);
同时释放 frozenBeanDefinitionNames,mergedBeanDefinitions 等中间元素值,供后续使用。还得处理 alias
元素

转载:http://www.verydemo.com/demo_c143_i3121.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: