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 + "]");
}
}
}
}
}