spring 加載應用上下文方式:
一、 從Web應用下的一個或多個XML配置文件中加載應用上下文
此上下文在 DispatchServlet
創建上下文時使用, 通過xml 啓動時創建web上下文.
ApplicationContext ac1 = new XmlWebApplicationContext();
FrameworkServlet.java
/**
* xml啓動的 web應用上下文
*/
public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;
/**
* 默認 XmlWebApplicationContext.class
*/
private Class<?> contextClass = DEFAULT_CONTEXT_CLASS;
public Class<?> getContextClass() {
return this.contextClass;
}
/**
* 創建web應用上下文,創建 XmlWebApplicationContext.class
*/
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
Class<?> contextClass = getContextClass();
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException("error");
}
ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setEnvironment(getEnvironment());
wac.setParent(parent);
String configLocation = getContextConfigLocation();
if (configLocation != null) {
wac.setConfigLocation(configLocation);
}
//配置與刷新web應用上下文
configureAndRefreshWebApplicationContext(wac);
return wac;
}
二、 從類路徑下的一個或多個XML配置文件中加載上下文定義,把應用上下文的定義文件作爲類資源
通過主動配置 xml 資源路徑, 創建應用上下文.
ApplicationContext ac2 = new ClassPathXmlApplicationContext();
ClassPathXmlApplicationContext
// demo
ApplicationContext context = new ClassPathXmlApplicationContext("/org/springframework/web/context/WEB-INF/applicationContext.xml");
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh(); // 在第二步:解析資源路徑
}
}
三、 從文件系統下的一個或多個XML配置中加載上下文定義
與 ClassPathXmlApplicationContext
相似, 在於 FileSystemXmlApplicationContext
初始化時, 可以直接url轉換 FileSystemResource
對象.
ApplicationContext ac3 = new FileSystemXmlApplicationContext();
protected Resource getResourceByPath(String path) {
if (path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
四、 從一個或多個基於Java的配置類中加載 應用上下文
註解配置上下文, 可通過註冊 @Configurable
註解配置的類來創建上下文,或者可通過配置掃描 package
路徑來創建上下文.
ApplicationContext ac4 = new AnnotationConfigApplicationContext();
AnnotationConfigApplicationContext
// 註解讀取器
private final AnnotatedBeanDefinitionReader reader;
// 路徑掃描器
private final ClassPathBeanDefinitionScanner scanner;
/**
* 註冊單個或者多個Bean
*/
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
this.reader.register(annotatedClasses);
}
/**
* 掃描給定的路徑
*/
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
this.scanner.scan(basePackages);
}
五、 從一個或多個基於Java的配置類中加載 Web應用上下文
註解配置web應用上下文, 可通過註冊 @Configurable
註解配置的類來創建web上下文,或者可通過配置掃描 package
路徑來創建web上下文. 重寫 loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
方法. 實現加載操作。
ApplicationContext ac5 = new AnnotationConfigWebApplicationContext();
/**
* 註冊一個或多個要處理的帶註釋的類
*/
public void register(Class<?>... annotatedClasses) {
Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
Collections.addAll(this.annotatedClasses, annotatedClasses);
}
/**
* 在指定的基本包中執行掃描
*/
public void scan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Collections.addAll(this.basePackages, basePackages);
}
/**
* 註冊一個{@link org.springframework.beans.factory.config.BeanDefinition}爲{@link #register(Class[])}指定的任何類,
* 掃描{@link #scan(String...)}指定的任何包
*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
if (!this.annotatedClasses.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Registering annotated classes: [" +
StringUtils.collectionToCommaDelimitedString(this.annotatedClasses) + "]");
}
reader.register(ClassUtils.toClassArray(this.annotatedClasses));
}
if (!this.basePackages.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Scanning base packages: [" +
StringUtils.collectionToCommaDelimitedString(this.basePackages) + "]");
}
scanner.scan(StringUtils.toStringArray(this.basePackages));
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
try {
Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
if (logger.isTraceEnabled()) {
logger.trace("Registering [" + configLocation + "]");
}
reader.register(clazz);
}
catch (ClassNotFoundException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Could not load class for config location [" + configLocation +
"] - trying package scan. " + ex);
}
int count = scanner.scan(configLocation);
if (count == 0 && logger.isDebugEnabled()) {
logger.debug("No annotated classes found for specified class/package [" + configLocation + "]");
}
}
}
}
}