- 浏览: 10492 次
- 性别:
- 来自: 山东-->北京
最新评论
-
wv1124:
不好用,早就不用了
可以同时测试ie5,ie6,ie7,id8...的浏览器 -
鹤惊昆仑:
linghongli 写道鹤惊昆仑 写道看看虚拟机方案。vir ...
可以同时测试ie5,ie6,ie7,id8...的浏览器 -
mgcnrx11:
ansjsun 写道linghongli 写道鹤惊昆仑 写道看 ...
可以同时测试ie5,ie6,ie7,id8...的浏览器 -
ansjsun:
linghongli 写道鹤惊昆仑 写道看看虚拟机方案。vir ...
可以同时测试ie5,ie6,ie7,id8...的浏览器 -
pipilu:
根本不顶用的。
可以同时测试ie5,ie6,ie7,id8...的浏览器
最近没事儿,就想看看spring是如何加载配置文件的(例如:applicationContext.xml),怕会忘掉,所以记下来:
1.入口
org.springframework.web.context.ContextLoaderListener(这里推荐使用listener,查了查原因,大部分是因为listener启动的时间更早)
//重要源码
/*--------------初始化入口---------------*/
/**
* Initialize the root web application context.
*/
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
this.contextLoader.initWebApplicationContext(event.getServletContext());
}
2.初始化过程
org.springframework.web.context.ContextLoader
//重要源码
/**
* Name of servlet context parameter (i.e., "<code>contextConfigLocation</code>")
* that can specify the config location for the root context, falling back
* to the implementation's default otherwise.
* @see org.springframework.web.context.support.XmlWebApplicationContext#DEFAULT_CONFIG_LOCATION
*/
public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";//这个就是在web.xml中配置的applicationContext.xml的键
/**
* Name of the class path resource (relative to the ContextLoader class)
* that defines ContextLoader's default strategy names.
*/
private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";//这个文件中配置了默认的ContextLoader
引用ContextLoader.properties中的内容:
# Default WebApplicationContext implementation class for ContextLoader.
# Used as fallback when no explicit context implementation has been specified as context-param.
# Not meant to be customized by application developers.
# 这里设置了默认的loder是org.springframework.web.context.support.XmlWebApplicationContext
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
/**
* Initialize Spring's web application context for the given servlet context,
* 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
* @throws IllegalStateException if there is already a root application context present
* @throws BeansException if the context failed to initialize
* @see #CONTEXT_CLASS_PARAM
* @see #CONFIG_LOCATION_PARAM
*/
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
......
// Determine parent for root web application context, if any.
// 取得父上下文环境。这里还没仔细看
ApplicationContext parent = loadParentContext(servletContext);
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
this.context = createWebApplicationContext(servletContext, parent);// ① 下面对这个进行说明
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);//将这个环境放入webapp的空共空间中
currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context);
}
/**
* Instantiate the root WebApplicationContext for this loader, either the
* default context class or a custom context class if specified.
* <p>This implementation expects custom contexts to implement the
* {@link ConfigurableWebApplicationContext} interface.
* Can be overridden in subclasses.
* <p>In addition, {@link #customizeContext} gets called prior to refreshing the
* context, allowing subclasses to perform custom modifications to the context.
* @param servletContext current servlet context
* @param parent the parent ApplicationContext to use, or <code>null</code> if none
* @return the root WebApplicationContext
* @throws BeansException if the context couldn't be initialized
* @see ConfigurableWebApplicationContext
*/
//对①的说明
protected WebApplicationContext createWebApplicationContext(
ServletContext servletContext, ApplicationContext parent) throws BeansException {
Class contextClass = determineContextClass(servletContext);//② 下面进行说明
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
}
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setParent(parent);
wac.setServletContext(servletContext);
wac.setConfigLocation(servletContext.getInitParameter(CONFIG_LOCATION_PARAM));
customizeContext(servletContext, wac);
//这个方法是一个非常深的模板方法 ③ 一会说明
wac.refresh();
return wac;
}
/**
* Return the WebApplicationContext implementation class to use, either the
* default XmlWebApplicationContext or a custom context class if specified.
* @param servletContext current servlet context
* @return the WebApplicationContext implementation class to use
* @throws ApplicationContextException if the context class couldn't be loaded
* @see #CONTEXT_CLASS_PARAM
* @see org.springframework.web.context.support.XmlWebApplicationContext
*/
//对②的说明
protected Class determineContextClass(ServletContext servletContext) throws ApplicationContextException {
//如果这里配置了CONTEXT_CLASS_PARAM参数,则加载这个类
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if (contextClassName != null) {
try {
return ClassUtils.forName(contextClassName);
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load custom context class [" + contextClassName + "]", ex);
}
}
else {
//否则,则从ContextLoader.properties中取得相应ApplicationContext的类进行加载
//这里默认的就是返回org.springframework.web.context.support.XmlWebApplicationContext这个类
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
try {
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load default context class [" + contextClassName + "]", ex);
}
}
}
下面来说一下比较负载的ConfigurableWebApplicationContext类,也是对③的说明
从上面的代码可以知道XmlWebApplicationContext是ConfigurableWebApplicationContext的实现类或者子类,看看他们的关系:
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext---》
//可以看到AbstractRefreshableWebApplicationContext实现了ConfigurableWebApplicationContext,但是这里面没有refresh()方法
//因为它在后面
public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource---》
//这里也没有,还在后面
public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext
implements BeanNameAware, InitializingBean---》
//这里也没有,不过里面有一个重要的方法:
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
......
/**
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
*/
//这个方法也是在其父类中被定义的,但是在它之中被实现的(也是一个模板)
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);//这个是重要的方法,在XmlWebApplicationContext中被实现了,一会看④
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException(
"I/O error parsing XML document for application context [" + getDisplayName() + "]", ex);
}
}
protected final void closeBeanFactory() {
synchronized (this.beanFactoryMonitor) {
this.beanFactory = null;
}
}
}---》
//这里面终于出现了refresh()方法
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext, DisposableBean {
......
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.
beanFactory.destroySingletons();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
}
//看一下⑤这个方法:
/**
* Tell the subclass to refresh the internal bean factory.
* @return the fresh BeanFactory instance
* @see #refreshBeanFactory()
* @see #getBeanFactory()
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();//还记得这个方法吗?
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isInfoEnabled()) {
logger.info("Bean factory for application context [" + getId() + "]: " +
ObjectUtils.identityToString(beanFactory));
}
if (logger.isDebugEnabled()) {
logger.debug(beanFactory.getBeanDefinitionCount() + " beans defined in " + this);
}
return beanFactory;
}
//下面看④这个方法,这个方法被是现在XmlWebApplicationContext类中:
/**
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
//看看loadBeanDefinitions(beanDefinitionReader)这个方法:
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//这个就是在web.xml中配置的:例如:
/*<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dataAccessContext-local.xml /WEB-INF/applicationContext.xml</param-value>
<!--
<param-value>/WEB-INF/dataAccessContext-jta.xml /WEB-INF/applicationContext.xml</param-value>
-->
</context-param>
*/
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (int i = 0; i < configLocations.length; i++) {
reader.loadBeanDefinitions(configLocations[i]);
}
}
}
//下面是reader.loadBeanDefinitions(configLocations[i]);
//这个方法在XmlBeanDefinitionReader的父类中实现的:
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {
......
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
public int loadBeanDefinitions(String location, Set actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int loadCount = loadBeanDefinitions(resources);//这又调用了子类的实现
if (actualResources != null) {
for (int i = 0; i < resources.length; i++) {
actualResources.add(resources[i]);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);//这又调用了子类的实现
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
}
//回到XmlBeanDefinitionReader看看resourceLoader.getResource这个方法:
/**
* Load bean definitions from the specified XML file.
* @param resource the resource descriptor for the XML file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
*/
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));//EncodedResource包装一下,生成InputStream对象
}
//loadBeanDefinitions(EncodedResource encodedResource)里面比较重要的方法:
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
......
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
......
}
//doLoadBeanDefinitions(InputSource inputSource, Resource resource)里面的重要方法:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
......
return registerBeanDefinitions(doc, resource);
......
}
//看看registerBeanDefinitions(doc, resource)方法:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// Support old XmlBeanDefinitionParser SPI for backwards-compatibility.
//说明是为了支持旧的的XmlBeanDefinitionParser,为了向后兼容
if (this.parserClass != null) {
XmlBeanDefinitionParser parser =
(XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);
return parser.registerBeanDefinitions(this, doc, resource);
}
// Read document based on new BeanDefinitionDocumentReader SPI.
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
//注意createReaderContext(resource)这个方法:
/*
protected XmlReaderContext createReaderContext(Resource resource) {
if (this.namespaceHandlerResolver == null) {
this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();//看看这个方法:
}
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, this.namespaceHandlerResolver);//⑥ 这里声明了XmlReaderContext
}
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());//⑦这里声明了NamespaceHandlerResolver
}
*/
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
//看看createBeanDefinitionDocumentReader()
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
//this.documentReaderClass在类中的值是:DefaultBeanDefinitionDocumentReader.class;
return (BeanDefinitionDocumentReader) BeanUtils.instantiateClass(this.documentReaderClass);
}
//所以下面要DefaultBeanDefinitionDocumentReader里面的registerBeanDefinitions方法了:
//接下来要做的就是指定解析器,进行xml文件的各种解析了
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
//这里声明了一个解析器的委托(委托这个类去办一些什么事呢?)
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
preProcessXml(root);
parseBeanDefinitions(root, delegate);//这个比较重要,看这个
postProcessXml(root);
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root.getNamespaceURI())) {
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;
String namespaceUri = ele.getNamespaceURI();
if (delegate.isDefaultNamespace(namespaceUri)) {
//这里解析一些默认的标签
parseDefaultElement(ele, delegate);
}
else {
//这个是我比较感兴趣的,比如annotation-config这种标签的解析
//所以重点看一下这个方法:
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
//去BeanDefinitionParserDelegate看看parseCustomElement这个方法:
public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = ele.getNamespaceURI();
//取得针对命名空间解析器的句柄
//this.readerContext = XmlReaderContext 就是⑥,getNamespaceHandlerResolver()返回的是⑦
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
//这里是要执行解析了,后面又是一个模板⑧
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
//看看this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
public NamespaceHandler resolve(String namespaceUri) {
//又是一个重要的,没有见过的方法
//如果map为空的,则初始化一个,但是里面都是字符串
Map handlerMappings = getHandlerMappings();
//最初取出来的为字符串
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
//由于最初的handlerOrClassName其实是字符串,所以不会进入这个分支的
else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler) handlerOrClassName;
}
else {
//初始时会进入这个分支,然后加载相应的class
String className = (String) handlerOrClassName;
try {
Class handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
//在这里进行初始化
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
namespaceHandler.init();//这个方法重要⑦
//覆盖原map中相应的值
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
namespaceUri + "] not found", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
namespaceUri + "]: problem with handler class file or dependent class", err);
}
}
}
//看看getHandlerMappings()方法:
/**
* Load the specified NamespaceHandler mappings lazily.
*/
//如果这个map是空的,则初始化它
private Map getHandlerMappings() {
if (this.handlerMappings == null) {
try {
//this.handlerMappingsLocation这个文件中的内容是:
/*
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/jms=org.springframework.jms.config.JmsNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler
http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
*/
//将配置文件中的键值存入map中,例如:"http\://www.springframework.org/schema/aop", "org.springframework.aop.config.AopNamespaceHandler"
//此时键和值都是字符串
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (logger.isDebugEnabled()) {
logger.debug("Loaded mappings [" + mappings + "]");
}
this.handlerMappings = new HashMap(mappings);
}
catch (IOException ex) {
IllegalStateException ise = new IllegalStateException(
"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]");
ise.initCause(ex);
throw ise;
}
}
return this.handlerMappings;
}
//下面来看⑦,举其中一个handler的例子,ContextNamespaceHandler:
//其实就是注册了很多的解析器,用来解析固定的标签
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerJava5DependentParser("annotation-config",
"org.springframework.context.annotation.AnnotationConfigBeanDefinitionParser");
registerJava5DependentParser("component-scan",
"org.springframework.context.annotation.ComponentScanBeanDefinitionParser");
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
//最后简单说说⑧
NamespaceHandlerSupport:BeanDefinition parse(Element element, ParserContext parserContext)---》
//它之用只定义了doParse方法
LoadTimeWeaverBeanDefinitionParser(以这个为例子,它复杂一些)extends AbstractSingleBeanDefinitionParser ---》
//parseInternal方法调用了其中的:doParse方法
AbstractSingleBeanDefinitionParser:protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext)
AbstractSingleBeanDefinitionParser extends AbstractBeanDefinitionParser ---》
//这个方法中调用了parseInternal(element, parserContext)方法,这个方法在其子类中实现,最后调用LoadTimeWeaverBeanDefinitionParser的doParse方法
AbstractBeanDefinitionParser:public final BeanDefinition parse(Element element, ParserContext parserContext)
1.入口
org.springframework.web.context.ContextLoaderListener(这里推荐使用listener,查了查原因,大部分是因为listener启动的时间更早)
//重要源码
/*--------------初始化入口---------------*/
/**
* Initialize the root web application context.
*/
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
this.contextLoader.initWebApplicationContext(event.getServletContext());
}
2.初始化过程
org.springframework.web.context.ContextLoader
//重要源码
/**
* Name of servlet context parameter (i.e., "<code>contextConfigLocation</code>")
* that can specify the config location for the root context, falling back
* to the implementation's default otherwise.
* @see org.springframework.web.context.support.XmlWebApplicationContext#DEFAULT_CONFIG_LOCATION
*/
public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation";//这个就是在web.xml中配置的applicationContext.xml的键
/**
* Name of the class path resource (relative to the ContextLoader class)
* that defines ContextLoader's default strategy names.
*/
private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";//这个文件中配置了默认的ContextLoader
引用ContextLoader.properties中的内容:
# Default WebApplicationContext implementation class for ContextLoader.
# Used as fallback when no explicit context implementation has been specified as context-param.
# Not meant to be customized by application developers.
# 这里设置了默认的loder是org.springframework.web.context.support.XmlWebApplicationContext
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
/**
* Initialize Spring's web application context for the given servlet context,
* 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
* @throws IllegalStateException if there is already a root application context present
* @throws BeansException if the context failed to initialize
* @see #CONTEXT_CLASS_PARAM
* @see #CONFIG_LOCATION_PARAM
*/
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
......
// Determine parent for root web application context, if any.
// 取得父上下文环境。这里还没仔细看
ApplicationContext parent = loadParentContext(servletContext);
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
this.context = createWebApplicationContext(servletContext, parent);// ① 下面对这个进行说明
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);//将这个环境放入webapp的空共空间中
currentContextPerThread.put(Thread.currentThread().getContextClassLoader(), this.context);
}
/**
* Instantiate the root WebApplicationContext for this loader, either the
* default context class or a custom context class if specified.
* <p>This implementation expects custom contexts to implement the
* {@link ConfigurableWebApplicationContext} interface.
* Can be overridden in subclasses.
* <p>In addition, {@link #customizeContext} gets called prior to refreshing the
* context, allowing subclasses to perform custom modifications to the context.
* @param servletContext current servlet context
* @param parent the parent ApplicationContext to use, or <code>null</code> if none
* @return the root WebApplicationContext
* @throws BeansException if the context couldn't be initialized
* @see ConfigurableWebApplicationContext
*/
//对①的说明
protected WebApplicationContext createWebApplicationContext(
ServletContext servletContext, ApplicationContext parent) throws BeansException {
Class contextClass = determineContextClass(servletContext);//② 下面进行说明
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
}
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setParent(parent);
wac.setServletContext(servletContext);
wac.setConfigLocation(servletContext.getInitParameter(CONFIG_LOCATION_PARAM));
customizeContext(servletContext, wac);
//这个方法是一个非常深的模板方法 ③ 一会说明
wac.refresh();
return wac;
}
/**
* Return the WebApplicationContext implementation class to use, either the
* default XmlWebApplicationContext or a custom context class if specified.
* @param servletContext current servlet context
* @return the WebApplicationContext implementation class to use
* @throws ApplicationContextException if the context class couldn't be loaded
* @see #CONTEXT_CLASS_PARAM
* @see org.springframework.web.context.support.XmlWebApplicationContext
*/
//对②的说明
protected Class determineContextClass(ServletContext servletContext) throws ApplicationContextException {
//如果这里配置了CONTEXT_CLASS_PARAM参数,则加载这个类
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if (contextClassName != null) {
try {
return ClassUtils.forName(contextClassName);
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load custom context class [" + contextClassName + "]", ex);
}
}
else {
//否则,则从ContextLoader.properties中取得相应ApplicationContext的类进行加载
//这里默认的就是返回org.springframework.web.context.support.XmlWebApplicationContext这个类
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
try {
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load default context class [" + contextClassName + "]", ex);
}
}
}
下面来说一下比较负载的ConfigurableWebApplicationContext类,也是对③的说明
从上面的代码可以知道XmlWebApplicationContext是ConfigurableWebApplicationContext的实现类或者子类,看看他们的关系:
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext---》
//可以看到AbstractRefreshableWebApplicationContext实现了ConfigurableWebApplicationContext,但是这里面没有refresh()方法
//因为它在后面
public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource---》
//这里也没有,还在后面
public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext
implements BeanNameAware, InitializingBean---》
//这里也没有,不过里面有一个重要的方法:
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
......
/**
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
*/
//这个方法也是在其父类中被定义的,但是在它之中被实现的(也是一个模板)
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);//这个是重要的方法,在XmlWebApplicationContext中被实现了,一会看④
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException(
"I/O error parsing XML document for application context [" + getDisplayName() + "]", ex);
}
}
protected final void closeBeanFactory() {
synchronized (this.beanFactoryMonitor) {
this.beanFactory = null;
}
}
}---》
//这里面终于出现了refresh()方法
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext, DisposableBean {
......
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.
beanFactory.destroySingletons();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
}
//看一下⑤这个方法:
/**
* Tell the subclass to refresh the internal bean factory.
* @return the fresh BeanFactory instance
* @see #refreshBeanFactory()
* @see #getBeanFactory()
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();//还记得这个方法吗?
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isInfoEnabled()) {
logger.info("Bean factory for application context [" + getId() + "]: " +
ObjectUtils.identityToString(beanFactory));
}
if (logger.isDebugEnabled()) {
logger.debug(beanFactory.getBeanDefinitionCount() + " beans defined in " + this);
}
return beanFactory;
}
//下面看④这个方法,这个方法被是现在XmlWebApplicationContext类中:
/**
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
//看看loadBeanDefinitions(beanDefinitionReader)这个方法:
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//这个就是在web.xml中配置的:例如:
/*<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/dataAccessContext-local.xml /WEB-INF/applicationContext.xml</param-value>
<!--
<param-value>/WEB-INF/dataAccessContext-jta.xml /WEB-INF/applicationContext.xml</param-value>
-->
</context-param>
*/
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (int i = 0; i < configLocations.length; i++) {
reader.loadBeanDefinitions(configLocations[i]);
}
}
}
//下面是reader.loadBeanDefinitions(configLocations[i]);
//这个方法在XmlBeanDefinitionReader的父类中实现的:
public abstract class AbstractBeanDefinitionReader implements BeanDefinitionReader {
......
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return loadBeanDefinitions(location, null);
}
public int loadBeanDefinitions(String location, Set actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int loadCount = loadBeanDefinitions(resources);//这又调用了子类的实现
if (actualResources != null) {
for (int i = 0; i < resources.length; i++) {
actualResources.add(resources[i]);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);//这又调用了子类的实现
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
}
//回到XmlBeanDefinitionReader看看resourceLoader.getResource这个方法:
/**
* Load bean definitions from the specified XML file.
* @param resource the resource descriptor for the XML file
* @return the number of bean definitions found
* @throws BeanDefinitionStoreException in case of loading or parsing errors
*/
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));//EncodedResource包装一下,生成InputStream对象
}
//loadBeanDefinitions(EncodedResource encodedResource)里面比较重要的方法:
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
......
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
......
}
//doLoadBeanDefinitions(InputSource inputSource, Resource resource)里面的重要方法:
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
......
return registerBeanDefinitions(doc, resource);
......
}
//看看registerBeanDefinitions(doc, resource)方法:
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// Support old XmlBeanDefinitionParser SPI for backwards-compatibility.
//说明是为了支持旧的的XmlBeanDefinitionParser,为了向后兼容
if (this.parserClass != null) {
XmlBeanDefinitionParser parser =
(XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);
return parser.registerBeanDefinitions(this, doc, resource);
}
// Read document based on new BeanDefinitionDocumentReader SPI.
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
//注意createReaderContext(resource)这个方法:
/*
protected XmlReaderContext createReaderContext(Resource resource) {
if (this.namespaceHandlerResolver == null) {
this.namespaceHandlerResolver = createDefaultNamespaceHandlerResolver();//看看这个方法:
}
return new XmlReaderContext(resource, this.problemReporter, this.eventListener,
this.sourceExtractor, this, this.namespaceHandlerResolver);//⑥ 这里声明了XmlReaderContext
}
protected NamespaceHandlerResolver createDefaultNamespaceHandlerResolver() {
return new DefaultNamespaceHandlerResolver(getResourceLoader().getClassLoader());//⑦这里声明了NamespaceHandlerResolver
}
*/
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
//看看createBeanDefinitionDocumentReader()
protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {
//this.documentReaderClass在类中的值是:DefaultBeanDefinitionDocumentReader.class;
return (BeanDefinitionDocumentReader) BeanUtils.instantiateClass(this.documentReaderClass);
}
//所以下面要DefaultBeanDefinitionDocumentReader里面的registerBeanDefinitions方法了:
//接下来要做的就是指定解析器,进行xml文件的各种解析了
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
//这里声明了一个解析器的委托(委托这个类去办一些什么事呢?)
BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
preProcessXml(root);
parseBeanDefinitions(root, delegate);//这个比较重要,看这个
postProcessXml(root);
}
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root.getNamespaceURI())) {
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;
String namespaceUri = ele.getNamespaceURI();
if (delegate.isDefaultNamespace(namespaceUri)) {
//这里解析一些默认的标签
parseDefaultElement(ele, delegate);
}
else {
//这个是我比较感兴趣的,比如annotation-config这种标签的解析
//所以重点看一下这个方法:
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
//去BeanDefinitionParserDelegate看看parseCustomElement这个方法:
public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = ele.getNamespaceURI();
//取得针对命名空间解析器的句柄
//this.readerContext = XmlReaderContext 就是⑥,getNamespaceHandlerResolver()返回的是⑦
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
//这里是要执行解析了,后面又是一个模板⑧
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
//看看this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
public NamespaceHandler resolve(String namespaceUri) {
//又是一个重要的,没有见过的方法
//如果map为空的,则初始化一个,但是里面都是字符串
Map handlerMappings = getHandlerMappings();
//最初取出来的为字符串
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
//由于最初的handlerOrClassName其实是字符串,所以不会进入这个分支的
else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler) handlerOrClassName;
}
else {
//初始时会进入这个分支,然后加载相应的class
String className = (String) handlerOrClassName;
try {
Class handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
//在这里进行初始化
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
namespaceHandler.init();//这个方法重要⑦
//覆盖原map中相应的值
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
namespaceUri + "] not found", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
namespaceUri + "]: problem with handler class file or dependent class", err);
}
}
}
//看看getHandlerMappings()方法:
/**
* Load the specified NamespaceHandler mappings lazily.
*/
//如果这个map是空的,则初始化它
private Map getHandlerMappings() {
if (this.handlerMappings == null) {
try {
//this.handlerMappingsLocation这个文件中的内容是:
/*
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.JeeNamespaceHandler
http\://www.springframework.org/schema/jms=org.springframework.jms.config.JmsNamespaceHandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.LangNamespaceHandler
http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
http\://www.springframework.org/schema/tx=org.springframework.transaction.config.TxNamespaceHandler
http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler
*/
//将配置文件中的键值存入map中,例如:"http\://www.springframework.org/schema/aop", "org.springframework.aop.config.AopNamespaceHandler"
//此时键和值都是字符串
Properties mappings =
PropertiesLoaderUtils.loadAllProperties(this.handlerMappingsLocation, this.classLoader);
if (logger.isDebugEnabled()) {
logger.debug("Loaded mappings [" + mappings + "]");
}
this.handlerMappings = new HashMap(mappings);
}
catch (IOException ex) {
IllegalStateException ise = new IllegalStateException(
"Unable to load NamespaceHandler mappings from location [" + this.handlerMappingsLocation + "]");
ise.initCause(ex);
throw ise;
}
}
return this.handlerMappings;
}
//下面来看⑦,举其中一个handler的例子,ContextNamespaceHandler:
//其实就是注册了很多的解析器,用来解析固定的标签
public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerJava5DependentParser("annotation-config",
"org.springframework.context.annotation.AnnotationConfigBeanDefinitionParser");
registerJava5DependentParser("component-scan",
"org.springframework.context.annotation.ComponentScanBeanDefinitionParser");
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}
//最后简单说说⑧
NamespaceHandlerSupport:BeanDefinition parse(Element element, ParserContext parserContext)---》
//它之用只定义了doParse方法
LoadTimeWeaverBeanDefinitionParser(以这个为例子,它复杂一些)extends AbstractSingleBeanDefinitionParser ---》
//parseInternal方法调用了其中的:doParse方法
AbstractSingleBeanDefinitionParser:protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext)
AbstractSingleBeanDefinitionParser extends AbstractBeanDefinitionParser ---》
//这个方法中调用了parseInternal(element, parserContext)方法,这个方法在其子类中实现,最后调用LoadTimeWeaverBeanDefinitionParser的doParse方法
AbstractBeanDefinitionParser:public final BeanDefinition parse(Element element, ParserContext parserContext)
相关推荐
1. **beans.xml**:这是Spring应用中最常见的配置文件,用于定义bean及其依赖关系。在这里,我们可以声明bean的类、属性、初始化方法、依赖注入等。 2. **applicationContext.xml**:此文件通常用于定义整个应用上...
总的来说,Spring动态加载配置文件的实现涉及到文件监听、配置文件解析、应用上下文刷新以及Web容器的协同。通过这样的机制,开发者可以在开发阶段快速响应配置的更改,提高开发效率,同时降低生产环境因重启服务...
这里的 `<import>` 标签指定了外部配置文件的路径,这些文件将在解析主配置文件时被自动加载和合并。 #### 四、结论 在 Spring 框架中,通过合理地拆分和加载多个配置文件,不仅可以显著提升应用程序的可读性和可...
这篇教程将详细讲解如何通过Spring的配置文件来实现AOP。 一、理解AOP概念 AOP的核心思想是将分散在各个模块中的交叉性代码(如日志、事务处理)抽取出来,形成独立的切面,以便于复用和维护。它提供了一种模块化的...
5. `spring-servlet.xml`: 这是Spring MVC的核心配置文件,配置了DispatcherServlet的处理器映射器、视图解析器、拦截器等,定义了Spring MVC的运行环境。 6. `web.xml`: 这是JavaWeb应用的部署描述符,定义了...
在Java开发中,Spring框架是应用最广泛的IoC(Inversion of Control)和AOP(Aspect Oriented Programming)容器。...在实际开发中,应根据项目需求选择合适的方式,确保配置文件能被正确地加载和解析。
1. **Mapper接口**:定义数据库操作的方法,与XML配置文件或注解对应。 2. **SQL映射文件**:编写具体的SQL语句,可以动态化处理,支持复杂的查询需求。 3. **MyBatis-Spring整合**:使MyBatis与Spring无缝集成,...
### Spring 最全约束配置文件知识点解析 #### 一、Spring框架简介 Spring是一个开源的Java应用框架,由Rod Johnson创建并领导开发。该框架的主要目标是简化企业级应用程序的开发,提供了一种轻量级的方式来处理...
本文将深入探讨如何模拟Spring的XML配置文件注入,并通过SAXBuilder解析XML文件来实现这一过程。 首先,理解XML配置文件在Spring中的作用至关重要。XML配置文件用于声明应用程序中的bean及其依赖关系,例如类的实例...
《Spring配置文件模板详解》 在Java开发领域,Spring框架以其强大的依赖注入(Dependency Injection,简称DI)和面向切面编程(Aspect-Oriented Programming,简称AOP)能力,成为了企业级应用开发的重要选择。而...
#### 二、Spring AOP配置文件解析 在给定的配置文件中,我们看到了一个典型的Spring AOP配置实例。接下来我们将对这段配置进行详细的分析与解读。 ##### 2.1 配置文件头 ```xml ``` 这是XML文档的声明部分,...
Spring框架是Java开发中最常用的轻量级框架之一,它的核心在于IoC(Inversion of Control,控制反转)和AOP(Aspect Oriented ...深入学习Spring4的jar包和配置文件,将使你更好地驾驭Java开发环境,提高软件工程能力。
Spring容器(ApplicationContext)会解析这些配置文件,创建并管理对象实例。 在Spring配置文件中,最重要的元素是`<bean>`。`<bean>`元素定义了一个Spring管理的对象,也称为bean。它包含几个关键属性,如`id`...
接下来,我们来配置Spring Boot的`application.yml`或`application.properties`文件以连接到Kafka集群。这里是一个示例配置: ```yaml spring: kafka: bootstrap-servers: localhost:9092 # Kafka服务器地址 ...
在本文中,我们将深入探讨Spring Security 3的配置文件,以及如何理解和使用这些配置来增强应用的安全性。 首先,Spring Security的配置通常位于一个或多个XML文件中,这些文件通过`<beans>`标签定义了安全相关的...
首先,Spring解析XML配置文件的过程是由`BeanDefinitionReader`完成的,它负责读取并解析XML文件,生成BeanDefinition对象。Spring提供了多种类型的BeanDefinitionReader,例如`XmlBeanDefinitionReader`,用于处理...
这些约束确保了配置文件的正确性,避免了因语法错误导致的解析问题。 Spring的XML配置文件通常包含以下元素的定义: 1. `<bean>`:表示一个Spring管理的Bean,定义其类、属性等。 2. `<context:component-scan>`:...
在实际项目中,这些配置文件会结合使用,形成一个完整的Spring MVC、Mybatis、Spring和oscache的集成环境,实现高效的数据访问、业务逻辑处理和页面展示。通过合理的配置,可以优化性能、增强可维护性和扩展性。