1. 程式人生 > >容器的功能擴充套件(二)功能擴充套件

容器的功能擴充套件(二)功能擴充套件

進入函式prepareBeanFactory前,Spring已經完成了對配置的解析,而ApplicationContext在功能上的擴充套件也由此展開。

	protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		//設定beanFactory的classLoader為當前context的classloader
		beanFactory.setBeanClassLoader(getClassLoader());
		//設定beanFactory的表示式語言處理器,Spring3增加了表示式語言的支援,
		//預設可以使用#{bean.xxx}的形式來呼叫相關屬性值
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver());
		//為beanFactory增加了一個預設的propertyEditor,這個主要是對bean的屬性等設定管理的一個工具
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		/*
		 * 新增BeanPostProcessor,
		 */
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		//設定了幾個忽略自動裝配的介面
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		//設定了幾個自動裝配的特殊 規則
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		// Detect a LoadTimeWeaver and prepare for weaving, if found.
		//增加對AspectJ的支援
		if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		// Register default environment beans.
		//新增預設的系統環境bean
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
	}

這些步驟看起來還有點模糊,接下來我們詳細分析各個步驟

1.增加SPEL語言支援

Spring表示式語言全稱為“Spring Expression Language”,縮寫為“SpEL”,類似於Struts 2x中使用的OGNL語言,SpEL是單獨模組,只依賴於core模組,不依賴於其他模組,可以單獨使用。

SpEL使用#{...}作為定界符,所有在大框號中的字元都將被認為是SpEL,使用格式如下:

	<util:properties id="db" location="classpath:db.properties">
	</util:properties>
	<bean id="dbcp" class="org.apache.commons.dbcp.BasicDataSource">
	  <property name="username" value="#{db.user}"></property>
	  <property name="password" value="#{db.pwd}"></property>
	  <property name="driverClassName" value="#{db.driver}"></property>
	  <property name="url" value="#{db.url}"></property>
	</bean>

上面只是列舉了其中最簡單的使用方式,SpEL功能非常強大,使用好可以大大提高開發效率。

在原始碼中通過程式碼beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver()),註冊語言解析器,就可以對SpEL進行解析了,那麼之後是在什麼地方呼叫這個解析器的呢?

之前說beanFactory中說過Spring在bean進行初始化的時候會有屬性填充的一步,而在這一步中Spring會呼叫AbstractAutowireCapabelBeanFactory類的applyPropertyValues來進行屬性值得解析。同時這個步驟中一般通過AbstractBeanFactory中的evaluateBeanDefinitionString方法進行SpEL解析:

	protected Object evaluateBeanDefinitionString(String value, BeanDefinition beanDefinition) {
		if (this.beanExpressionResolver == null) {
			return value;
		}
		Scope scope = (beanDefinition != null ? getRegisteredScope(beanDefinition.getScope()) : null);
		return this.beanExpressionResolver.evaluate(value, new BeanExpressionContext(this, scope));
	}

當呼叫這個方法時會判斷是否有語言解析器,如果存在則呼叫語言解析器,解析的過程在Spring的expression包裡。

2.新增ApplicationContextAwareProcessor處理器

beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));其實主要目的就是註冊個BeanPostProcessor,而真正的邏輯實現還是在ApplicationContextAwareProcessor中。

ApplicationContextAwareProcessor實現了BeanPostProcessor介面,我們看下之前說過的東西,在bean例項化的時候,也就是Spring啟用bean的init-method的前後,會呼叫BeanProcessor的postProcessBeforeInitialization方法和postProcessAfterInitialization方法。同樣,對於ApplicationContextAwareProcessor也有這兩個方法。

對於postProcessAfterInitialization方法,在ApplicationContextAwareProcessor中並沒有做過多處理。

	public Object postProcessAfterInitialization(Object bean, String beanName) {
		return bean;
	}

重點看下postProcessBeforeInitialization方法:
	public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
		AccessControlContext acc = null;

		if (System.getSecurityManager() != null &&
				(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
						bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
						bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {
			acc = this.applicationContext.getBeanFactory().getAccessControlContext();
		}

		if (acc != null) {
			AccessController.doPrivileged(new PrivilegedAction<Object>() {
				public Object run() {
					invokeAwareInterfaces(bean);
					return null;
				}
			}, acc);
		}
		else {
			invokeAwareInterfaces(bean);
		}

		return bean;
	}

	private void invokeAwareInterfaces(Object bean) {
		if (bean instanceof Aware) {
			if (bean instanceof EnvironmentAware) {
				((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
			}
			if (bean instanceof EmbeddedValueResolverAware) {
				((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(
						new EmbeddedValueResolver(this.applicationContext.getBeanFactory()));
			}
			if (bean instanceof ResourceLoaderAware) {
				((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
			}
			if (bean instanceof ApplicationEventPublisherAware) {
				((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
			}
			if (bean instanceof MessageSourceAware) {
				((MessageSourceAware) bean).setMessageSource(this.applicationContext);
			}
			if (bean instanceof ApplicationContextAware) {
				((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
			}
		}
	}

postProcessBeforeInitialization方法中呼叫了invokeAwareInterfaces。從invokeAwareInterfaces方法中,我們可以看出來,實現這些Aware介面的bean在被初始化之後,可以取得一些對應的資源。

3.設定忽略依賴

Spring將ApplicationContextAwareProcessor註冊後,在invokeAwareInterfaces方法中間呼叫的Aware類已經不是普通的bean了,如ResourceLoaderAware,ApplicationEventPublisherAware等,那麼當然需要在Spring做bean的依賴注入的時候忽略它們。而ignoreDependencyInterface的作用正是如此。

		//設定了幾個忽略自動裝配的介面
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);

4.註冊依賴

Spring中有忽略依賴的功能,也有註冊依賴的功能。

		//設定了幾個自動裝配的特殊 規則
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

當註冊了依賴解析後,例如當註冊了對BeanFactory.class的解析後,當bean的屬性注入的時候,一旦檢測到屬性為BeanFactory型別便會將beanFactory的例項注入進去。

可能有些朋友有些迷糊,為什麼剛剛實現了介面又忽略依賴注入,剛忽略介面的依賴注入,下面又增加了註冊依賴的功能?

因為在Spring載入bean的時候,還會將實現的介面依賴進去,因為是單例模式的,這些介面已經在spring的其他模組做了依賴處理,在此不需要重複依賴。