(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();
		}
  另外,lookup-method & replace-method 用于哪些地方呢?
共同点主要用于:
单例类调用原型类,默认情况被调用的原形类仍是单例模式(即单例模式覆盖了原型模式),而通过lookup-method属性给单例类注入原型模式类的不同的实例。
他们之间有 什么区别呢?
其实很多时候 使用Autowired 即可,但是,使用场景还是有所不同的。Autowired用于给一个单例对象注入另一个单例对象。但是如果想注入另外一个原型对象。那么久行不通了!这个时候就使用lookup-method 吧!

 二、XmlWebApplicationContext的实现:

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

其中,ConfigurableWebApplicationContext->WebApplicationContext->ApplicationContext

 

 

 

 

 

猜你喜欢

转载自1181731633.iteye.com/blog/2344502