以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属性给单例类注入原型模式类的不同的实例。
他们之间有 什么区别呢?
其实很多时候 使用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(); }
相关推荐
Spring MVC的初始化则是在Spring容器初始化之后进行的。在`web.xml`中,我们配置了一个`DispatcherServlet`,这个Servlet是Spring MVC的核心,它有自己的ApplicationContext,也就是子容器。`DispatcherServlet`的`...
这一步至关重要,因为`ContextLoaderListener`负责在应用启动时加载Spring的配置文件,建立并初始化Spring IoC容器。配置示例如下: ```xml org.springframework.web.context.ContextLoaderListener ``` ...
当我们谈论“ContextLoader加载XML”时,我们关注的是如何通过XML配置文件来定义和初始化Spring的IoC容器。 XML配置文件是Spring早期版本中最常见的配置方式,它以XML格式定义了bean的元数据,包括bean的类型、属性...
在ApplicationContext中,除了初始化方法,还有更多的生命周期回调,如预初始化、后初始化等。销毁方法通常在容器关闭时调用。 依赖注入方式: Spring支持多种依赖注入方式,包括构造函数注入、属性注入(set方法...
当我们谈论“加载Spring文件,在web.xml中的配置”时,主要是指如何在Web应用启动时初始化Spring IoC(Inversion of Control,控制反转)容器并加载配置文件。 1. **使用ContextLoaderListener** `<listener>`标签...
在非Web环境下,Spring容器可以通过ClassPathResource、FileSystemResource或者InputStreamResource加载XML配置文件,然后创建XmlBeanFactory或ApplicationContext实例来初始化容器。例如,我们可以从classpath路径...
Spring框架的初始化与XML解析是其核心功能之一,它使得开发者可以轻松地管理对象和依赖关系,从而实现控制反转(IOC)和面向切面编程(AOP)。在深入讲解之前,我们先理解Spring的基本概念。Spring是一个开源的Java...
在Web应用中,ApplicationContext的初始化常通过`ContextLoaderListener`在web.xml中配置完成,这样可以确保在Web服务器启动时加载Spring容器。配置如下: ```xml <param-name>contextConfigLocation ...
1. `BeanFactory`:基础的IOC容器,负责初始化和管理Bean,以及调用它们的生命周期方法。配置信息通常通过XML文件提供,如`applicationContext.xml`。 2. `ApplicationContext`:BeanFactory的增强版,增加了国际化...
2. **配置Spring监听器**:在`web.xml`文件中,需要配置一个Spring的上下文监听器`ContextLoaderListener`,该监听器负责初始化Spring的ApplicationContext。具体配置如下所示: ```xml <listener-class>org....
【Spring在Web项目中的应用】 ...同时,通过监听器`ContextLoaderListener`,可以在Web容器启动时自动加载Spring配置,确保在整个Web应用程序生命周期中,Service层和其他Spring管理的bean都可以正确地被创建和管理。
而在Web项目中,由于需要在Web服务器启动时初始化容器,因此会利用`ContextLoaderListener`监听器。在`web.xml`配置文件中,设置`<context-param>`和`<listener>`元素,指定配置文件的位置,这样当Web服务器启动时,...
同时在`web.xml`中配置`ContextLoaderListener`监听器,使得Spring的IoC容器在应用启动时初始化。这种方式使得Struts在运行时能够通过Spring获取Action实例。 2. 直接在`web.xml`中加载Spring配置: 这种方式下,...
- ContextLoaderListener监听器在Web应用启动时加载指定的Spring配置文件,完成IOC容器的初始化。 2. **Spring MVC配置** - DispatcherServlet作为Spring MVC的前端控制器,负责请求分发。 - 通过配置文件...
这种方式使得 Spring 容器能够在 Struts 初始化时加载,从而管理应用中的所有bean。 2. **使用 ContextLoaderListener 监听器** 另一种启动 Spring 容器的方法是在 `web.xml` 中配置 `ContextLoaderListener` ...
2. `listener`: `ContextLoaderListener`是一个监听器,它会在Web应用启动时加载配置文件并初始化Spring IoC容器。 3. `filter`: `FilterDispatcher`是Struts2的核心过滤器,负责处理HTTP请求。在整合Spring后,它会...
这个监听器是 Spring 的 `ContextLoaderListener` 和 Servlet API 的 `ServletContextListener` 的子类,它在Web应用程序启动时执行一些关键的初始化任务。在 `web.xml` 文件中配置这个监听器,使得容器在启动时能够...
在Servlet容器中,`ContextLoaderListener`首先加载,初始化Spring应用上下文。然后Filter按照配置的顺序开始过滤HTTP请求。 9. Redis使用场景和数据格式: Redis不仅可以用于缓存,还可用作消息队列、计数器、...
2. 添加监听器:配置Spring的ContextLoaderListener,用于初始化Spring容器,并实例化Struts2中的Action。 3. 修改`Struts.xml`:配置Action,使其与Spring的bean结合。 4. 日志配置:引入日志框架如Log4j或SLF4J,...
但不管是 ContextLoaderSevlet还是 ContextLoaderListener都使用ContextLoader来完成实际的WebApplicationContext的初始化工作。这个ContextLoder就像是Spring Web应用程序在Web容器中的加载器booter。当然这些...