容器的功能擴充套件(二)功能擴充套件
進入函式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的其他模組做了依賴處理,在此不需要重複依賴。