`

(IOC)ContextLoaderListener容器加载初始化

 
阅读更多

以jetty服务器为例:

引用:ContextLoaderListener监听器的作用就是启动Web容器时,自动装配ApplicationContext的配置信息。因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。

附:初始化bean最终执行的好像都是org.springframework.beans.BeanUtils.java类的方法。

 

一、容器启动加载内容:

      可是,启动容器时,ContextLoaderListener实现类的监听器在哪里被调用的呢,比如jetty,其实是被org.mortbay.jetty.handler.ContextHandler类调用的,再往上看,就是org.mortbay.jetty.webapp.WebAppContext的doStart方法。由ContextHandler成员变量_contextListeners.contextInitialized(event);在项目启动时来调用,而此时的event参数,是servlet-api-x.x.jar中的ServletContext接口,实现类由不同web容器各自实现,比如jetty为ContextHandler中的SContext。

所以,容器启动时会调用所有此监听器实现类,那么就可以通过实现类做点什么...

配置文件如下(其中名字contextConfigLocation不能变,它是ContextLoader类中的常量):

    <listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath*:applicationContext-*.xml,/WEB-INF/applicationContext.xml,/WEB-INF/classes/applicationContext-*.xml  
lt;/param-value>
	</context-param> 

 加载好的容器对象为WebApplicationContext,并将其放入ServletContext中(供所有servlet使用)。而WebApplicationContext的默认实现类为XmlWebApplicationContext,查看源码可得,在/org/springframework/web/context/ContextLoader.properties配置默认的容器类。XmlWebApplicationContext初始化如下:

1、被ContextLoader调用configureAndRefreshWebApplicationContext(cwac, servletContext);初始化Bean工厂类以及其他配置

2、默认读取配置文件:DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml",我们一般自己定义,有多个时用;分开,这个配置在上面有提到。

 

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...值为(例):org.springframework.web.context.WebApplicationContext:/findhome-web
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(sc.getContextPath()));
			}
		}

		wac.setServletContext(sc);
		String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (configLocationParam != null) {
			wac.setConfigLocation(configLocationParam);//值为(例):classpath:spring.xml
		}

		// The wac environment's #initPropertySources will be called in any case when the context
		// is refreshed; do it eagerly here to ensure servlet property sources are in place for
		// use in any post-processing or initialization that occurs below prior to #refresh
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
		}

		customizeContext(sc, wac);
		wac.refresh();//初始化
	}

 

其中wac.refresh();初始化的内容如下:初始化加载bean,其中通过判断是否开启Scanner扫描注解方式,并生成对应的bean。扫描到的bean放在beanFactory,用于后面的加载。

 

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) {
				logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

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

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

 

 

其中,执行finishBeanFactoryInitialization(beanFactory);时,装载所有非延迟加载的单例,会针对每个bean进行实例化,其实无论是数据库配置,还是redis、消息队列等第三方功能组件,都是配置一个bean类放到spring工厂中提供调用,其需要的参数不同,在配置中配置对应需要的参数即可。点进去可看的如下代码:

 

@Override
	public void preInstantiateSingletons() throws BeansException {
		if (this.logger.isDebugEnabled()) {
			this.logger.debug("Pre-instantiating singletons in " + this);
		}

		// Iterate over a copy to allow for init methods which in turn register new bean definitions.
		// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
		List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);

		// Trigger initialization of all non-lazy singleton beans...
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				if (isFactoryBean(beanName)) {
					final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
							@Override
							public Boolean run() {
								return ((SmartFactoryBean<?>) factory).isEagerInit();
							}
						}, getAccessControlContext());
					}
					else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
				else {
					getBean(beanName);
				}
			}
		}

		// Trigger post-initialization callback for all applicable beans...
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged(new PrivilegedAction<Object>() {
						@Override
						public Object run() {
							smartSingleton.afterSingletonsInstantiated();
							return null;
						}
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}
 

 

遍历所有单例,并通过getBean()初始化,而getBean()调用底层方法,可以看看它的实现,在源码中可以看的,类A加载时如果依赖B,那就先去加载B,再回来加载A。其中,生成对象的createBean(beanName, mbd, args);方法中,有一句代码很重要,如下:

 

Object beanInstance = doCreateBean(beanName, mbdToUse, args);
 看看它的实现,

 

 

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
		// 实际创建的Bean的包装容器
		BeanWrapper instanceWrapper = null;
		
		//对于单例模式下的Bean,可能在创建过程中断过,暂时放在缓存里
		if (mbd.isSingleton()) {
			//从缓存中恢复未创建完成的Bean对象
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
			//真正创建对象的入口
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
		Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);

		// Allow post-processors to modify the merged bean definition.
		//Bean创建后处理
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				mbd.postProcessed = true;
			}
		}

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		// 解决循环引用的地方,当singleton遇到循环引用时,会放入singletonsCurrentlyInCreation中,暂停
		// 在此处从singletonsCurrentlyInCreation中再拿到这个未完成初始化的对象
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isDebugEnabled()) {
				logger.debug("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			addSingletonFactory(beanName, new ObjectFactory<Object>() {
				@Override
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, mbd, bean);
				}
			});
		}

		// 下面依赖注入
		Object exposedObject = bean;
		try {
			//依赖注入的方法入口
			populateBean(beanName, mbd, instanceWrapper);
			if (exposedObject != null) {
				exposedObject = initializeBean(beanName, exposedObject, mbd);
			}
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}
		// 处理未完成注入的循环引用的bean
		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}
 继续往下看,

 

 

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
		//获得需要创建的Bean的Class
		Class<?> beanClass = resolveBeanClass(mbd, beanName);
		// 确定需要创建的Bean的实例的类可以实例化
		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}
		//如果存在工厂方法,则使用工厂方法去实例化类
		if (mbd.getFactoryMethodName() != null)  {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// 使用自动状态的构造方式进行实例化
		// 下面10行的代码是在减少重复创建bean的工作量。如果已经创建过同样的bean,直接使用上一次的配置属性
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		//自动装配构造实例
		if (resolved) {
			if (autowireNecessary) {
				//返回自动装配的实例化结果
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				//使用构造方法进行构造
				return instantiateBean(beanName, mbd);
			}
		}

		// 确定需要使用的构造方法
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null ||
				mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
					//自动装配构造方法
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// 使用默认的无参数的构造方法
		return instantiateBean(beanName, mbd);
	}
 其中,instantiateBean方法如下:

 

 

protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
		try {
			Object beanInstance;//构建出来的Bean实例
			final BeanFactory parent = this;
			if (System.getSecurityManager() != null) {
				// 提升权限  
				beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
					@Override
					public Object run() {
						//调用具体实例化方法
						return getInstantiationStrategy().instantiate(mbd, beanName, parent);
					}
				}, getAccessControlContext());
			}
			else {
				//调用具体实例化方法
				beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
			}
			//包装创建好的实例
			BeanWrapper bw = new BeanWrapperImpl(beanInstance);
			initBeanWrapper(bw);
			return bw;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
		}
	}
 继续,这里有两种初始化方式,使用JDK的反射方法、CGLIB的方法:
另外,lookup-method & replace-method 用于哪些地方呢?
共同点主要用于:
单例类调用原型类,默认情况被调用的原形类仍是单例模式(即单例模式覆盖了原型模式),而通过lookup-method属性给单例类注入原型模式类的不同的实例。
他们之间有 什么区别呢?
其实很多时候 使用Autowired 即可,但是,使用场景还是有所不同的。Autowired用于给一个单例对象注入另一个单例对象。但是如果想注入另外一个原型对象。那么久行不通了!这个时候就使用lookup-method 吧!
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
		// 这个if-else 把bean的初始化分为两类
		//如果定义了look-up method(针对虚拟类获取原型bean的虚拟方法) 或replace method(用继承MethodReplacer接口的类来做) 将使用CGLIB初始化
		//否则使用JDK的反射
		if (bd.getMethodOverrides().isEmpty()) {
			Constructor<?> constructorToUse;//获得构造方法
			synchronized (bd.constructorArgumentLock) {
				//使用工厂方法  或者 构造器
				constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					final Class<?> clazz = bd.getBeanClass();
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if (System.getSecurityManager() != null) {
							constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
								@Override
								public Constructor<?> run() throws Exception {
									return clazz.getDeclaredConstructor((Class[]) null);
								}
							});
						}
						else {
							constructorToUse =	clazz.getDeclaredConstructor((Class[]) null);
						}
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Exception ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// 使用CGLIB初始化
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}
 而两种初始化方式代码分别为:
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
		Assert.notNull(ctor, "Constructor must not be null");
		try {
			//获得访问权限
			ReflectionUtils.makeAccessible(ctor);
			//利用反射生成实例
			return ctor.newInstance(args);
		}
		catch (InstantiationException ex) {
			throw new BeanInstantiationException(ctor.getDeclaringClass(),
					"Is it an abstract class?", ex);
		}
		catch (IllegalAccessException ex) {
			throw new BeanInstantiationException(ctor.getDeclaringClass(),
					"Is the constructor accessible?", ex);
		}
		catch (IllegalArgumentException ex) {
			throw new BeanInstantiationException(ctor.getDeclaringClass(),
					"Illegal arguments for constructor", ex);
		}
		catch (InvocationTargetException ex) {
			throw new BeanInstantiationException(ctor.getDeclaringClass(),
					"Constructor threw exception", ex.getTargetException());
		}
	}
 
public Object instantiate(Constructor<?> ctor, Object... args) {
			//利用CGLIB生成Class对象
			Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
			Object instance;
			if (ctor == null) {
				//利用反射对CGLIB生成的Class对象实例化
				instance = BeanUtils.instantiate(subclass);
			}
			else {
				try {
					Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
					//利用CGLIB进行实例化
					instance = enhancedSubclassConstructor.newInstance(args);
				}
				catch (Exception ex) {
					throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
							"Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
				}
			}
			// SPR-10785: set callbacks directly on the instance instead of in the
			// enhanced class (via the Enhancer) in order to avoid memory leaks.
			
			//在此处设置lookup和replacemethod
			Factory factory = (Factory) instance;

			factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
					new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
					new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
			return instance;
		}
 
private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
			Enhancer enhancer = new Enhancer();
			enhancer.setSuperclass(beanDefinition.getBeanClass());
			enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
			enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
			enhancer.setCallbackTypes(CALLBACK_TYPES);
			return enhancer.createClass();
		}
 

 二、XmlWebApplicationContext的实现:

首先,XmlWebApplicationContext->AbstractRefreshableWebApplicationContext->AbstractRefreshableConfigApplicationContext和ConfigurableWebApplicationContext,

其中,ConfigurableWebApplicationContext->WebApplicationContext->ApplicationContext

 

 

 

 

 

 

分享到:
评论

相关推荐

    浅谈Spring与SpringMVC父子容器的关系与初始化

    Spring MVC的初始化则是在Spring容器初始化之后进行的。在`web.xml`中,我们配置了一个`DispatcherServlet`,这个Servlet是Spring MVC的核心,它有自己的ApplicationContext,也就是子容器。`DispatcherServlet`的`...

    在Struts 2中实现IoC

    这一步至关重要,因为`ContextLoaderListener`负责在应用启动时加载Spring的配置文件,建立并初始化Spring IoC容器。配置示例如下: ```xml org.springframework.web.context.ContextLoaderListener ``` ...

    ContextLoader 加载xml

    当我们谈论“ContextLoader加载XML”时,我们关注的是如何通过XML配置文件来定义和初始化Spring的IoC容器。 XML配置文件是Spring早期版本中最常见的配置方式,它以XML格式定义了bean的元数据,包括bean的类型、属性...

    spring的ppt

    在ApplicationContext中,除了初始化方法,还有更多的生命周期回调,如预初始化、后初始化等。销毁方法通常在容器关闭时调用。 依赖注入方式: Spring支持多种依赖注入方式,包括构造函数注入、属性注入(set方法...

    加载spring 文件,在web.xml中的配置

    当我们谈论“加载Spring文件,在web.xml中的配置”时,主要是指如何在Web应用启动时初始化Spring IoC(Inversion of Control,控制反转)容器并加载配置文件。 1. **使用ContextLoaderListener** `&lt;listener&gt;`标签...

    Spring学习资料

    在非Web环境下,Spring容器可以通过ClassPathResource、FileSystemResource或者InputStreamResource加载XML配置文件,然后创建XmlBeanFactory或ApplicationContext实例来初始化容器。例如,我们可以从classpath路径...

    Spring的初始化和XML解析的实现

    Spring框架的初始化与XML解析是其核心功能之一,它使得开发者可以轻松地管理对象和依赖关系,从而实现控制反转(IOC)和面向切面编程(AOP)。在深入讲解之前,我们先理解Spring的基本概念。Spring是一个开源的Java...

    专题资料(2021-2022年)Java项目教学第一学期SSM框架讲义1Spring的基本应用.docx

    在Web应用中,ApplicationContext的初始化常通过`ContextLoaderListener`在web.xml中配置完成,这样可以确保在Web服务器启动时加载Spring容器。配置如下: ```xml &lt;param-name&gt;contextConfigLocation ...

    Java项目教学第一学期-SSM框架讲义1-Spring的基本应用.pdf

    1. `BeanFactory`:基础的IOC容器,负责初始化和管理Bean,以及调用它们的生命周期方法。配置信息通常通过XML文件提供,如`applicationContext.xml`。 2. `ApplicationContext`:BeanFactory的增强版,增加了国际化...

    struts加载spring的方法

    2. **配置Spring监听器**:在`web.xml`文件中,需要配置一个Spring的上下文监听器`ContextLoaderListener`,该监听器负责初始化Spring的ApplicationContext。具体配置如下所示: ```xml &lt;listener-class&gt;org....

    Web项目中使用Spring, 使用 Spring 的器监听器 ContextLoaderListener.docx

    【Spring在Web项目中的应用】 ...同时,通过监听器`ContextLoaderListener`,可以在Web容器启动时自动加载Spring配置,确保在整个Web应用程序生命周期中,Service层和其他Spring管理的bean都可以正确地被创建和管理。

    基于java的企业级应用开发:Spring的核心容器.ppt

    而在Web项目中,由于需要在Web服务器启动时初始化容器,因此会利用`ContextLoaderListener`监听器。在`web.xml`配置文件中,设置`&lt;context-param&gt;`和`&lt;listener&gt;`元素,指定配置文件的位置,这样当Web服务器启动时,...

    Struts Spring Hibernate 整合引用2008

    同时在`web.xml`中配置`ContextLoaderListener`监听器,使得Spring的IoC容器在应用启动时初始化。这种方式使得Struts在运行时能够通过Spring获取Action实例。 2. 直接在`web.xml`中加载Spring配置: 这种方式下,...

    MyBatis_3_整合Spring3、SpringMVC

    - ContextLoaderListener监听器在Web应用启动时加载指定的Spring配置文件,完成IOC容器的初始化。 2. **Spring MVC配置** - DispatcherServlet作为Spring MVC的前端控制器,负责请求分发。 - 通过配置文件...

    spring和struts整合的三种方案

    这种方式使得 Spring 容器能够在 Struts 初始化时加载,从而管理应用中的所有bean。 2. **使用 ContextLoaderListener 监听器** 另一种启动 Spring 容器的方法是在 `web.xml` 中配置 `ContextLoaderListener` ...

    学习笔记之struts2整合Spring

    2. `listener`: `ContextLoaderListener`是一个监听器,它会在Web应用启动时加载配置文件并初始化Spring IoC容器。 3. `filter`: `FilterDispatcher`是Struts2的核心过滤器,负责处理HTTP请求。在整合Spring后,它会...

    AppFuse项目研究

    这个监听器是 Spring 的 `ContextLoaderListener` 和 Servlet API 的 `ServletContextListener` 的子类,它在Web应用程序启动时执行一些关键的初始化任务。在 `web.xml` 文件中配置这个监听器,使得容器在启动时能够...

    12Spring以及框架相关面试问题汇总1

    在Servlet容器中,`ContextLoaderListener`首先加载,初始化Spring应用上下文。然后Filter按照配置的顺序开始过滤HTTP请求。 9. Redis使用场景和数据格式: Redis不仅可以用于缓存,还可用作消息队列、计数器、...

    ssh框架整合文档

    2. 添加监听器:配置Spring的ContextLoaderListener,用于初始化Spring容器,并实例化Struts2中的Action。 3. 修改`Struts.xml`:配置Action,使其与Spring的bean结合。 4. 日志配置:引入日志框架如Log4j或SLF4J,...

    spring源代码解析

    但不管是 ContextLoaderSevlet还是 ContextLoaderListener都使用ContextLoader来完成实际的WebApplicationContext的初始化工作。这个ContextLoder就像是Spring Web应用程序在Web容器中的加载器booter。当然这些...

Global site tag (gtag.js) - Google Analytics