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
2. Create event
3. Publish the event
Servlet 的 观察者例子如下:
二、Spring 容器启动的入口点
Spring 容器启动的一种方式为配置 web.xml,加入如下行
Spring 容器启动的原理如下:
2.1. Servlet (Jetty)容器启动,会读取 web project 的 WEB-INF/web.xml 文件,并使用 web.xml 的相关配置,初始化 ServletContext (JettyWebContext),该 context 包括 web 自身的一些信息。如 Servlet 的版本号,用户 web project 所在的绝对路劲等。例如:
然后当读到 <listener> 元素时,调用 Spring 容器的:
注: ContextLoadListener 在加载的时候,会通过其父类的 <cinit> 方法,读取 properties 配置文件,将 XmlWebApplicationContext 作为容器初始化的默认方式。
2.2 其中 initWebApplicationContext 内容如下:
三、 Spring refresh
该方法调用
// Initialize any placeholder property sources in the context environment
initPropertySources();
首先创建 StandardServletEnvironment 对象,该对象实现 ConfigurableWebEnvironment 接口。初始化如下一些属性[servletConfigInitParams,servletContextInitParams,jndiProperties,systemProperties,systemEnvironment] 作为 environment 的 propertySources (MutablePropertySources)属性。
servletConfigInitParams 的值为 servlet 初始化的 servletConfig 值 null.
systemProperties = System.getProperties() 值:
该方法调用 初始化一个 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。
该方法还调用 方法:
实现如下功能:
首先该方法通过如下代码查找由 web.xml 中配置的 Spring 全局XML 配置文件文件。
String[] configLocations = getConfigLocations();
由下代码便可知我们 project 中默认的 applicationContext.xml 的由来。 这也是 Spring 的一个常用规则:
到处设置默认值,便于用户使用。
reader.loadBeanDefinitions(configLocation);
return loadBeanDefinitions(location, null);
Resource[] = ((ResourcePatternResolver) resourceLoader).getResources(location);
----> 其值为
int loadCount = loadBeanDefinitions(resources);
XmlBeanDefinitionReader :
doLoadBeanDefinitions(inputSource, encodedResource.getResource());
doRegisterBeanDefinitions(Element root)
--> BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createHelper(readerContext, root, parent);
元素包含的属性如下:
现在逻辑为通过 parseBeanDefinitions(root, this.delegate);
[b]解析[/b] bean 元素:其代码如下:
DefaultNamespace为beans的非默认元素(如 context, mvc等),用delegate.parseCustomElement(ele);[b]解析[/b]
DefaultNamespace 不为 beans,则通过 delegate.parseCustomElement(root);
[b]解析[/b]
我们先看第一种请客:
--> parseBeanDefinitionElement(ele, null);
元素对应的 BeanDefinition,验证一定的逻辑之后,将其存入 beanFacotry 相关容器中,供后面程序使用。
this..add(beanName);
this..put(beanName, beanDefinition);
同时释放 frozenBeanDefinitionNames,mergedBeanDefinitions 等中间元素值,供后续使用。还得处理 alias
元素。
转载:http://www.verydemo.com/demo_c143_i3121.html
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
相关文章推荐
- 一、从 BeanDefinitionParserDelegate 解析xml bean元素,查看bean的各个属性(Spring3.2.12)
- Spring源码学习--Bean注入解析结果BeanDefinition
- Spring BeanFactory、ApplicationContext层次结构和BeanDefinition解析过程
- spring解析xml中的bean的一个关键类public class BeanDefinitionParserDelegate
- 辛星解析Spring3.2源码第二篇:BeanDefinitionReaderUtils
- Spring源码阅读之IoC容器初始化2 -- BeanDefinition载入与解析
- 【spring源码分析】BeanDefinitionRegistryPostProcessor接口可自定义bean加入IOC
- Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析
- Spring源码分析-BeanDefinition加载、解析和注册
- 解析Spring源码(8)--BeanDefinitionParserDelegate
- Spring源码学习--Spring配置文件解析BeanDefinitionReader(二)
- 6-spring源码3.2.18解读+spring技术内幕(关于BeanDefinition的载入和解析)
- 死磕Spring系列之二,bean标签的解析和BeanDefinition的注册
- spring源码(8)注册解析的BeanDefinition
- Spring源码解析--Spring配置文件解析BeanDefinitionParserDelegate(四)
- Spring 源码阅读 BeanFactory(二) 之registerBeanDefinition方法
- Spring3.2 中 Bean 定义之基于 XML 配置方式的源码解析
- spring 技术内幕--IOC初始化过程深入之BeanDefinition的载入和解析1
- 【Spring源码--IOC容器的实现】(三)BeanDefinition的载入和解析【I】
- spring IOC源码之解析xml中各个元素的过程