Spring原始碼解析筆記8——容器的功能擴充套件ApplicationContext
ApplicationContext包含BeanFactory的所有功能,並且可以對BeanFactory現有的功能進行擴充套件。絕大多數典型的企業應用和系統,使用的都是ApplicationContext而不是直接使用BeanFactory。下面看一下ApplicationContext相對於BeanFactory擴充套件了哪些功能。
//BeanFactory的載入配置檔案的方式:
BeanFactory bf = new XmlBeanFactory(new ClassPathResource("beanFactoryTest.xml"));
//ApplicationContext載入配置檔案的方式:
ApplicationContext bf = new ClassPathXmlApplicationContext("");
繼續根據ClassPathXmlApplicationContext進行跟蹤:
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[]{configLocation}, true, (ApplicationContext)null);
}
//根據this繼續走:
public ClassPathXmlApplicationContext (String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
//將配置檔案的路徑以陣列的方式傳入。
this.setConfigLocations(configLocations);
if(refresh) {
//解析和功能實現。
this.refresh();
}
}
繼續跟蹤setConfigLocations:
public void setConfigLocations(String... locations) {
if(locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for(int i = 0; i < locations.length; ++i) {
//解析給定路徑,如果陣列總包含特殊符號,如${var},那麼resolvePath中會搜尋系統的變數被替換。
this.configLocations[i] = this.resolvePath(locations[i]).trim();
}
} else {
this.configLocations = null;
}
}
繼續跟蹤refresh函式:
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
//準備重新整理上下文環境,例如對系統屬性或者環境變數進行準備及驗證。
this.prepareRefresh();
//初始化BeanFactory,並進行XML檔案的讀取,這一步驟要服用BeanFactory的配置檔案讀取的以及其他功能。
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//對BeanFactory進行各種功能填充。@Qualifier和@Autowired是在此步驟增加的支援。
this.prepareBeanFactory(beanFactory);
try {
//子類覆蓋方法做額外的處理。
this.postProcessBeanFactory(beanFactory);
//啟用各種BeanFactory處理器
this.invokeBeanFactoryPostProcessors(beanFactory);
//註冊攔截Bean建立的Bean處理器,這裡只是註冊,真正的呼叫是在getBean的時候
this.registerBeanPostProcessors(beanFactory);
//為上下文初始化Mesagge源,即不同語言的訊息體,國際化處理。
this.initMessageSource();
//初始化應用訊息廣播器,並放入applicationEventMulticaster中
this.initApplicationEventMulticaster();
//留給子類來初始化其他的bean
this.onRefresh();
//在所有註冊的bean中查詢Listener bean,註冊到訊息廣播器中。
this.registerListeners();
//初始化剩下的單例。
this.finishBeanFactoryInitialization(beanFactory);
//完成重新整理過程。
this.finishRefresh();
} catch (BeansException var9) {
if(this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
繼續跟蹤refresh方法中的this.prepareRefresh()方法:
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if(this.logger.isInfoEnabled()) {
this.logger.info("Refreshing " + this);
}
//留給子類覆蓋。
this.initPropertySources();
//驗證需要的屬性檔案是否都已經放入環境中。
this.getEnvironment().validateRequiredProperties();
this.earlyApplicationEvents = new LinkedHashSet();
}
上述留給子類覆蓋的方法initPropertySources使用舉例:
class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{
public MyClassPathXmlApplicationContext(String ... configLocations) {
super(configLocations);
}
@Override
protected void initPropertySources() {
getEnvironment().setRequiredProperties("VAR");
}
}
//讀取配置檔案時這樣呼叫:
ApplicationContext bf2 = new MyClassPathXmlApplicationContext("");
繼續跟蹤refresh方法中的this.obtainFreshBeanFactory()方法:
//通過了這個函式以後,ApplicationContext就已經擁有了BeanFactory的全部功能。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//初始化BeanFactory,並進行XML檔案讀取,並將得到的BeanFactory記錄在當前實體的屬性中,
this.refreshBeanFactory();
//返回當前實體的beanFactory
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
if(this.logger.isDebugEnabled()) {
this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
//上面的this.refreshBeanFactory()方法原始碼:
protected final void refreshBeanFactory() throws BeansException {
if(this.hasBeanFactory()) {
this.destroyBeans();
this.closeBeanFactory();
}
try {
//建立DefaultListableBeanFactory
DefaultListableBeanFactory ex = this.createBeanFactory();
//為了反序列化指定id,如果需要,讓這個BeanFactory從id反序列化到BeanFactory物件。
ex.setSerializationId(this.getId());
//定製beanFactory,設定相關屬性,包括是否允許覆蓋同名稱的不同定義的物件以及迴圈依賴
//設定@Autowired和@Qualitier註冊解析器QualifierAnnotationAutowireCandidateResolver
this.customizeBeanFactory(ex);
//初始化DocumentReader,並進行XML檔案讀取及解析。
this.loadBeanDefinitions(ex);
Object var2 = this.beanFactoryMonitor;
synchronized(this.beanFactoryMonitor) {
this.beanFactory = ex;
}
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
}
}
//跟蹤上面的this.customizeBeanFactory(ex)方法:
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
//是否允許覆蓋同名稱的不同定義的物件。
if(this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding.booleanValue());
}
//是否允許bean之間存在迴圈依賴。
if(this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences.booleanValue());
}
}
//關於上面方法中allowBeanDefinitionOverriding和allowCircularReferences的變數設定舉例:
class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext{
@Override
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
super.setAllowBeanDefinitionOverriding(false);
super.setAllowCircularReferences(false);
super.customizeBeanFactory(beanFactory);
}
}
//繼續走this.loadBeanDefinitions(ex),此方法是用來載入BeanDefinition
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//對上一步建立的beanDefinitionReader進行環境變數的設定。
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//對beanDefinitionReader進行設定,可以覆蓋。
this.initBeanDefinitionReader(beanDefinitionReader);
this.loadBeanDefinitions(beanDefinitionReader);
}
//繼續檢視this.loadBeanDefinitions(beanDefinitionReader)
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = this.getConfigResources();
if(configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = this.getConfigLocations();
if(configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
繼續跟蹤refresh方法中的this.prepareBeanFactory(beanFactory)
//原始碼如下:
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//設定beanFactory的classLoader為當前的classLoader。
beanFactory.setBeanClassLoader(this.getClassLoader());
//預設可以使用EL表示式
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
//為beanFactory增加了一個預設propertyEditor,主要是對bean的屬性等設定管理的一個工具。
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, this.getEnvironment()));
//新增PostProcessor
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
//設定幾個自動裝配的特殊規則
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
//增加對ApectJ的支援
if(beanFactory.containsBean("loadTimeWeaver")) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}
if(!beanFactory.containsLocalBean("environment")) {
beanFactory.registerSingleton("environment", this.getEnvironment());
}
if(!beanFactory.containsLocalBean("systemProperties")) {
beanFactory.registerSingleton("systemProperties", this.getEnvironment().getSystemProperties());
}
//增加預設環境bean.
if(!beanFactory.containsLocalBean("systemEnvironment")) {
beanFactory.registerSingleton("systemEnvironment", this.getEnvironment().getSystemEnvironment());
}
}
/**
setBeanExpressionResolver註冊語言解析器,就可以對SPEL進行解析了,
真正呼叫這個解析器是在Spring對bean進行初始化時的屬性填充這步,
在這一步中Spring會呼叫AbstractAutowireCapableBeanFactory類中的applyPropertyValues函式來完成。
**/
上述方法中對bean的屬性等設定管理說明:在SpringDI注入的時候可以把普通屬性注入進來,但是像Date這種型別就無法被識別。例如:
class UserManager{
private Date dataValue;
public Date getDataValue() {
return dataValue;
}
public void setDataValue(Date dataValue) {
this.dataValue = dataValue;
}
}
//上述程式碼中需要對日期型別的屬性進行注入:
<bean id="userManager" class com.test.UserManager>
<property name="dataValue">
<value>2013-03-15</value>
</property>
</bean>
//測試
ApplicationContext bf = new ClassPathXmlApplicationContext("");
UserManager userManager = (UserManager)bf.getBean("userManager");
System.out.println(userManager);
如果直接這樣使用,程式會報錯,型別轉換不成功。String無法轉換成Date型別。spring針對這類問題提供了兩種解決辦法:
1.自定義屬性編輯器,通過繼承PropertyEditorSupport.
//編寫自定義的屬性編輯器
class DatePropertyEditor extends PropertyEditorSupport{
private String format = "yyyy-MM-dd";
public void setFormat(String format) {
this.format = format;
}
public void setAsText(String arg0) throws IllegalArgumentException{
SimpleDateFormat sdf = new SimpleDateFormat(format);
try {
Date d = sdf.parse(arg0);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
//將自定義屬性編輯器註冊到Spring中。
<bean class="org.Springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="java.util.Date">
<bean class="com.test.DatePropertyEditor">
<property name="format" value="yyyy-MM-dd"/>
</bean>
</map>
</property>
</bean>
2.註冊Spring自帶的屬性編輯器CustomDateEditor
//定義屬性編輯器
class DatePropertyEditorRegostrar implements PropertyEditorRegistrar{
@Override
public void registerCustomEditors(PropertyEditorRegistry propertyEditorRegistry) {
propertyEditorRegistry.registerCustomEditor(Date.class,new CustomDateEditor(new SimpleDateFormat("yyyy-MM-dd"),true));
}
}
//註冊到spring
<bean class="org.Springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="com.test.DatePropertyEditorRegistrar"></bean>
</list>
</property>
</bean>
ResourceEditorRegistrar中也實現了registerCustomEditors方法:
//原始碼如下:
public void registerCustomEditors(PropertyEditorRegistry registry) {
ResourceEditor baseEditor = new ResourceEditor(this.resourceLoader, this.propertyResolver);
this.doRegisterEditor(registry, Resource.class, baseEditor);
this.doRegisterEditor(registry, ContextResource.class, baseEditor);
this.doRegisterEditor(registry, InputStream.class, new InputStreamEditor(baseEditor));
this.doRegisterEditor(registry, InputSource.class, new InputSourceEditor(baseEditor));
this.doRegisterEditor(registry, File.class, new FileEditor(baseEditor));
if(pathClass != null) {
this.doRegisterEditor(registry, pathClass, new PathEditor(baseEditor));
}
this.doRegisterEditor(registry, Reader.class, new ReaderEditor(baseEditor));
this.doRegisterEditor(registry, URL.class, new URLEditor(baseEditor));
ClassLoader classLoader = this.resourceLoader.getClassLoader();
this.doRegisterEditor(registry, URI.class, new URIEditor(classLoader));
this.doRegisterEditor(registry, Class.class, new ClassEditor(classLoader));
this.doRegisterEditor(registry, Class[].class, new ClassArrayEditor(classLoader));
if(this.resourceLoader instanceof ResourcePatternResolver) {
this.doRegisterEditor(registry, Resource[].class, new ResourceArrayPropertyEditor((ResourcePatternResolver)this.resourceLoader, this.propertyResolver));
}
}
//繼續追蹤doRegisterEditor:
private void doRegisterEditor(PropertyEditorRegistry registry, Class<?> requiredType, PropertyEditor editor) {
if(registry instanceof PropertyEditorRegistrySupport) {
((PropertyEditorRegistrySupport)registry).overrideDefaultEditor(requiredType, editor);
} else {
//前面提到的自定義屬性的關鍵程式碼在此被呼叫
registry.registerCustomEditor(requiredType, editor);
}
}
查找了registerCustomEditors方法被呼叫的位置,發現AbstractBeanFactory類中的initBeanWrapper方法呼叫了此方法,這個方法是在bean初始化時使用的一個方法,主要作用就是將BeanDefinition轉換為BeanWrapper後用於屬性的填充。在bean初始化以後會呼叫ResourceEditorRegistrar的registerCustomEditors方法進行批量的通用屬性編輯器註冊。註冊後,在屬性填充的環節便可以直接讓Spring使用這些編輯器進行屬性的解析了。
BeanWrapper除了實現了BeanWrapperImpl還繼承了PropertyEditorRegistrySupport,在該類中有這樣一個方法:
/**
通過這個方法可以知道在spring中定義了上面一系列常用的屬性編輯器,
如果我們定義的bean中的某個屬性的型別不在上面的常用配置中,才需要我們進行個性化屬性編輯器的註冊。
**/
private void createDefaultEditors() {
this.defaultEditors = new HashMap(64);
this.defaultEditors.put(Charset.class, new CharsetEditor());
this.defaultEditors.put(Class.class, new ClassEditor());
this.defaultEditors.put(Class[].class, new ClassArrayEditor());
this.defaultEditors.put(Currency.class, new CurrencyEditor());
this.defaultEditors.put(File.class, new FileEditor());
this.defaultEditors.put(InputStream.class, new InputStreamEditor());
this.defaultEditors.put(InputSource.class, new InputSourceEditor());
this.defaultEditors.put(Locale.class, new LocaleEditor());
if(pathClass != null) {
this.defaultEditors.put(pathClass, new PathEditor());
}
this.defaultEditors.put(Pattern.class, new PatternEditor());
this.defaultEditors.put(Properties.class, new PropertiesEditor());
this.defaultEditors.put(Reader.class, new ReaderEditor());
this.defaultEditors.put(Resource[].class, new ResourceArrayPropertyEditor());
this.defaultEditors.put(TimeZone.class, new TimeZoneEditor());
this.defaultEditors.put(URI.class, new URIEditor());
this.defaultEditors.put(URL.class, new URLEditor());
this.defaultEditors.put(UUID.class, new UUIDEditor());
if(zoneIdClass != null) {
this.defaultEditors.put(zoneIdClass, new ZoneIdEditor());
}
this.defaultEditors.put(Collection.class, new CustomCollectionEditor(Collection.class));
this.defaultEditors.put(Set.class, new CustomCollectionEditor(Set.class));
this.defaultEditors.put(SortedSet.class, new CustomCollectionEditor(SortedSet.class));
this.defaultEditors.put(List.class, new CustomCollectionEditor(List.class));
this.defaultEditors.put(SortedMap.class, new CustomMapEditor(SortedMap.class));
this.defaultEditors.put(byte[].class, new ByteArrayPropertyEditor());
this.defaultEditors.put(char[].class, new CharArrayPropertyEditor());
this.defaultEditors.put(Character.TYPE, new CharacterEditor(false));
this.defaultEditors.put(Character.class, new CharacterEditor(true));
this.defaultEditors.put(Boolean.TYPE, new CustomBooleanEditor(false));
this.defaultEditors.put(Boolean.class, new CustomBooleanEditor(true));
this.defaultEditors.put(Byte.TYPE, new CustomNumberEditor(Byte.class, false));
this.defaultEditors.put(Byte.class, new CustomNumberEditor(Byte.class, true));
this.defaultEditors.put(Short.TYPE, new CustomNumberEditor(Short.class, false));
this.defaultEditors.put(Short.class, new CustomNumberEditor(Short.class, true));
this.defaultEditors.put(Integer.TYPE, new CustomNumberEditor(Integer.class, false));
this.defaultEditors.put(Integer.class, new CustomNumberEditor(Integer.class, true));
this.defaultEditors.put(Long.TYPE, new CustomNumberEditor(Long.class, false));
this.defaultEditors.put(Long.class, new CustomNumberEditor(Long.class, true));
this.defaultEditors.put(Float.TYPE, new CustomNumberEditor(Float.class, false));
this.defaultEditors.put(Float.class, new CustomNumberEditor(Float.class, true));
this.defaultEditors.put(Double.TYPE, new CustomNumberEditor(Double.class, false));
this.defaultEditors.put(Double.class, new CustomNumberEditor(Double.class, true));
this.defaultEditors.put(BigDecimal.class, new CustomNumberEditor(BigDecimal.class, true));
this.defaultEditors.put(BigInteger.class, new CustomNumberEditor(BigInteger.class, true));
if(this.configValueEditorsActive) {
StringArrayPropertyEditor sae = new StringArrayPropertyEditor();
this.defaultEditors.put(String[].class, sae);
this.defaultEditors.put(short[].class, sae);
this.defaultEditors.put(int[].class, sae);
this.defaultEditors.put(long[].class, sae);
}
}
繼續跟蹤this.prepareBeanFactory(beanFactory)方法中的beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));,該方法主要還是用來註冊BeanPostProcessor.
/**
該方法的重要邏輯都在ApplicationContextAwareProcessor中。
前面幾章提到過Spring啟用bean的init-method的前後,會呼叫BeanPostProcessor中的
postProcessBeforeInitialization和postProcessAfterInitialization方法。
ApplicationContextAwareProcessor類的原始碼實現:
**/
class ApplicationContextAwareProcessor implements BeanPostProcessor {
private final ConfigurableApplicationContext applicationContext;
private final StringValueResolver embeddedValueResolver;
public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
this.applicationContext = applicationContext;
this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
}
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() {
public Object run() {
ApplicationContextAwareProcessor.this.invokeAwareInterfaces(bean);
return null;
}
}, acc);
} else {
this.invokeAwareInterfaces(bean);
}
return bean;
}
//通過此方法可以看出實現了Aware介面的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(this.embeddedValueResolver);
}
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);
}
}
}
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
}