首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > XML SOAP >

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

2013-01-28 
Spring 3.2源码解析 -- XML bean 元素到 BeanDefinition 解析过程package com.colorcc.test.event.listene

Spring 3.2 源码解析 -- XML bean 元素到 BeanDefinition 解析过程
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;}@Overridepublic 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 {@Overridepublic 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 所在的绝对路劲等。例如:

ServletContext@o.m.j.p.JettyWebAppContext{/,file:/opt/dev/workspace_jack/register-api/src/main/webapp/},file:/opt/dev/workspace_jack/register-api/src/main/webapp/

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

public class ContextLoaderListener extends ContextLoader implements ServletContextListener {        ...? ? ? ?// Listener 的具体实现,这是 Spring 容器通过 XML 配置方式的直接入口点       // 其中 ServletContextEvent 中包含了一个 ServletContext,为Servlet 容器初始化了,传递给 Spring 供后继使用       public void contextInitialized(ServletContextEvent event) {? ? ? ? ? ? ? ? // 兼容低版本的 Springthis.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,创建一个新的 WebApplicationContextif (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 informationString 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.xmlString initParameter = sc.getInitParameter(CONFIG_LOCATION_PARAM);if (initParameter != null) {wac.setConfigLocation(initParameter);}// 通过 String classNames = servletContext.getInitParameter("contextInitializerClasses")// 检查是否有 ApplicationContextInitializer<ConfigurableApplicationContext> 元素,如果有则// 继续初始化customizeContext(sc, wac);// 核心逻辑:刷新 ApplicationContextwac.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;}}}?/** 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 值。{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);}}?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());}?最终调用方法 loadBeanDefinitions(beanFactory); 实现 XML 元素的解析功能。@Overrideprotected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {// Create a new XmlBeanDefinitionReader for the given BeanFactory.? ? ? ? ? ? ? ? // 创建 XmlBeanDefinitionReaderXmlBeanDefinitionReader 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); // 通过该方法解析 XML 文件loadBeanDefinitions(beanDefinitionReader);}分析 loadBeanDefinitions(XmlBeanDefinitionReader reader) 方法/** 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};}}?最终调用的一些业务逻辑代码如下:public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {return loadBeanDefinitions(new EncodedResource(resource));}protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {int validationMode = getValidationModeForResource(resource);// 通过调用 JAXP 解析 applicationContext.xml 文件为 Document 对象Document doc = this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());return registerBeanDefinitions(doc, resource);} ...}?根据 Document 对象,解析其中每个元素:
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 文件,解析其中的 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) 的调用逻辑为: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;?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);解析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)) {// recursedoRegisterBeanDefinitions(ele);}}?解析 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);public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {// 对应解析XML文件的 id, name 元素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);}// 解析 <bean> 元素的属性值,如 +"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.// 解析 bean 对应的 attribute 属性,如:// [autowire="default", autowire-candidate="default", class="iteye-blog-content-contain">?

热点排行