- 使用 Spring Initializr 创建 Spring Boot 应用程序
- 在Spring Boot中配置Cassandra
- 在 Spring Boot 上配置 Tomcat 连接池
- 将Camel消息路由到嵌入WildFly的Artemis上
上一篇解析了 DispatcherServlet
与 ContextLoaderListener
这两个类,解析了应用初始化与请求处理的流程,但还有一些组件需要解析:
ConfigurableWebApplicationContext.refresh
刷新上下文ApplicationContext.getBean
从上下文中获取 beanDispatcherServlet.properties
文件中定义的策略处理ContextLoader.properties
文件中定义的策略处理View.render
视图渲染这一章来看看 ContextLoader.properties
文件中定义的策略处理
ContextLoader.properties
文件中只定义了一个策略
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
默认使用 XmlWebApplicationContext
(基于 XML 加载)作为应用上下文
spring-web
内部定义 5 个应用上下文类:
WebApplicationContext
的基础实现,但不能通过配置文件和注解加载应用配置与 bean,一般用于扩展实现(如 SpringBoot),很少直接使用WebApplicationContext
的基础实现,但不支持 i18n,主要用于测试,不用产品环境WebApplicationContext
实现,是 SpringMVC 的默认 Context@Configuration, @bean
等加载应用配置与 bean 的WebApplicationContext
实现XmlWebApplicationContext
的实现差不多,但可以用 Groovy 代替 xml 做配置文件,目前用得不多先来看看这 5 个应用上下文类各自的继承关系
- DefaultResourceLoader
- AbstractApplicationContext
- GenericApplicationContext
- GenericWebApplicationContext
- DefaultResourceLoader
- AbstractApplicationContext
- GenericApplicationContext
- StaticApplicationContext
- StaticWebApplicationContext
- DefaultResourceLoader
- AbstractApplicationContext
- AbstractRefreshableApplicationContext
- AbstractRefreshableConfigApplicationContext
- AbstractRefreshableWebApplicationContext
- XmlWebApplicationContext
- DefaultResourceLoader
- AbstractApplicationContext
- AbstractRefreshableApplicationContext
- AbstractRefreshableConfigApplicationContext
- AbstractRefreshableWebApplicationContext
- AnnotationConfigWebApplicationContext
- DefaultResourceLoader
- AbstractApplicationContext
- AbstractRefreshableApplicationContext
- AbstractRefreshableConfigApplicationContext
- AbstractRefreshableWebApplicationContext
- GroovyWebApplicationContext
我们可以发现每个类都继承 AbstractApplicationContext
,而 XmlWebApplicationContext
, AnnotationConfigWebApplicationContext
,GroovyWebApplicationContext
都继承 AbstractRefreshableWebApplicationContext
DefaultResourceLoader
的主要功能是实现资源加载
public class DefaultResourceLoader implements ResourceLoader {}
先来看看接口ResourceLoader
public interface ResourceLoader {
// 根据一个字符位置信息获取资源
Resource getResource(String location);
// 获取资源加载器
ClassLoader getClassLoader();
}
DefaultResourceLoader
是 ResourceLoader
的默认实现
public class DefaultResourceLoader implements ResourceLoader {
@Override
public ClassLoader getClassLoader() {
// 如果有指定的classLoader,则返回指定的,没有则返回默认的
return (this.classLoader != null ? this.classLoader : ClassUtils.getDefaultClassLoader());
}
@Override
public Resource getResource(String location) {
// 自定义协议解析
for (ProtocolResolver protocolResolver : getProtocolResolvers()) {
Resource resource = protocolResolver.resolve(location, this);
if (resource != null) {
return resource;
}
}
// 如果以/开头,则认为是classpath资源
if (location.startsWith("/")) {
return getResourceByPath(location);
}
// 如果以classpath:开头的classpath资源
else if (location.startsWith(CLASSPATH_URL_PREFIX)) {
return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());
}
else {
try {
// 尝试以文件或url对待
URL url = new URL(location);
return (ResourceUtils.isFileURL(url) ? new FileUrlResource(url) : new UrlResource(url));
}
catch (MalformedURLException ex) {
// 失败则默认是classpath资源
return getResourceByPath(location);
}
}
}
}
AbstractApplicationContext
的主要功能是通过名字、类型或注解获取 bean 实例,获取上下文的环境对象与资源、刷新上下文数据
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {}
接口 ConfigurableApplicationContext
及其继承的接口主要定义以下的方法
public interface ConfigurableApplicationContext {
// 获取bean
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
// 通过类型或注解获取bean
<T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException;
<T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException;
Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
// 获取环境
ConfigurableEnvironment getEnvironment();
// 刷新上下文数据
void refresh() throws BeansException, IllegalStateException;
// 根据locationPattern获取多个资源,如通配符*
Resource[] getResources(String locationPattern) throws IOException;
}
AbstractApplicationContext.getEnvironment
获取环境
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}
protected ConfigurableEnvironment createEnvironment() {
// 内置的标准环境(也可以通过setEnvironment方法自定义环境处理机制)
// 这是可以使用 `application-dev.yml, application-test.yml, application-prod.yml, ...` 来根据环境加载不同的配置的底层实现
// 是spring-boot的基本功能
return new StandardEnvironment();
}
}
AbstractApplicationContext.getBean
获取 bean
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public Object getBean(String name) throws BeansException {
return getBeanFactory().getBean(name);
}
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
return getBeanFactory().getBean(name, requiredType);
}
@Override
public Object getBean(String name, Object... args) throws BeansException {
return getBeanFactory().getBean(name, args);
}
@Override
public <T> T getBean(Class<T> requiredType) throws BeansException {
return getBeanFactory().getBean(requiredType);
}
@Override
public <T> T getBean(Class<T> requiredType, Object... args) throws BeansException {
return getBeanFactory().getBean(requiredType, args);
}
// 留给子类实现
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
因为不同的Context
注册 bean 的方式不一样,所以getBeanFactory
留给子类来实现
AbstractApplicationContext.getBeansOfType
通过类型或注解获取 bean
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type) throws BeansException {
return getBeanFactory().getBeansOfType(type);
}
@Override
public <T> Map<String, T> getBeansOfType(@Nullable Class<T> type, boolean includeNonSingletons, boolean allowEagerInit)
throws BeansException {
return getBeanFactory().getBeansOfType(type, includeNonSingletons, allowEagerInit);
}
@Override
public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType)
throws BeansException {
return getBeanFactory().getBeansWithAnnotation(annotationType);
}
// 留给子类实现
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}
AbstractApplicationContext.refresh
刷新上下文数据
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// ... 代码省略
// 初始化事件容器与监听器,检查必须的属性配置,并载入必要的实例
prepareRefresh();
// 刷新上下文的bean,获取bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 预备bean工厂
prepareBeanFactory(beanFactory);
try {
// 后置处理bean工厂
postProcessBeanFactory(beanFactory);
// ... 代码省略
// 调用bean工厂的后置处理器,以使在所有bean实例化之前,可以自定义添加自己的BeanPostProcessor(bean实例化后置操作)
invokeBeanFactoryPostProcessors(beanFactory);
// 给bean工厂注册BeanPostProcessor(bean实例化后置操作)
registerBeanPostProcessors(beanFactory);
// ... 代码省略
// 实例化applicationEventMulticaster bean,作为应用事件广播器
initApplicationEventMulticaster();
// 扩展实现,留给开发者,默认不实现
onRefresh();
// 注册应用事件监听器
registerListeners();
// 初始化所有单例的bean
finishBeanFactoryInitialization(beanFactory);
// 刷新上下文数据完成,做一些后续处理
finishRefresh();
}
catch (BeansException ex) {
// ... 代码省略
}
finally {
// ... 代码省略
}
}
}
// 刷新上下文的bean,获取bean工厂
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 刷新上下文的bean
refreshBeanFactory();
// 获取bean工厂
return getBeanFactory();
}
// 刷新上下文的bean,由子类实现
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException;
// 获取bean工厂,由子类实现
public abstract ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
// 扩展实现,留给开发者,默认不实现
protected void onRefresh() throws BeansException {}
// 初始化所有单例的bean
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
// ... 代码省略
// 固化所有bean的配置,后面不再更改
beanFactory.freezeConfiguration();
// 初始化所有单例的bean
beanFactory.preInstantiateSingletons();
}
// 刷新上下文数据完成,做一些后续处理
protected void finishRefresh() {
// 清除一些资源缓存
clearResourceCaches();
// 实例化lifecycleProcessor bean
initLifecycleProcessor();
// 实例化Lifecycle bean,并调用这些bean的start方法
getLifecycleProcessor().onRefresh();
// 派发事件
publishEvent(new ContextRefreshedEvent(this));
// ... 代码省略
}
}
Context
注册 bean 的方式不一样,所以refreshBeanFactory, postProcessBeanFactory
留给子类来实现ConfigurableListableBeanFactory
如何加载、实例化 bean,后面再解析AbstractApplicationContext.prepareBeanFactory
预备 bean 工厂
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// ... 代码省略
// 添加对 #{} SpEL Spring 表达式语言的支持
if (!shouldIgnoreSpel) {
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
}
// 添加属性编辑器,xml、yaml 中定义的值转换成对象就是依赖这里实现的
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
// 添加一个BeanPostProcessor,后置处理器
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// ... 代码省略
// 注册几个可以autowirable自动载入的实例
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// ... 代码省略
// 注册几个单例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());
}
if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
}
}
}
ResourceEditorRegistrar
如何注册属性编辑器、属性编辑器如何解析为对象,后面再解析AbstractApplicationContext.getResources
根据 locationPattern 获取多个资源,如通配符*
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
private ResourcePatternResolver resourcePatternResolver;
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
@Override
public Resource[] getResources(String locationPattern) throws IOException {
return this.resourcePatternResolver.getResources(locationPattern);
}
}
PathMatchingResourcePatternResolver
如何解析、加载 locationPattern 指定的资源,后面再解析总的来说,AbstractApplicationContext
类完成上下文环境的大部分功能,包括环境加载、bean 的加载与前置后置处理、事件派发、完成一些初始化工作等,
但扩展了几个接口给子类实现,如如何加载、注册、实例化 bean 等
GenericApplicationContext
的主要功能是注册、管理 bean 的定义与别名
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {}
BeanDefinitionRegistry
这个接口主要定义了注册 bean 的定义及别名
public interface BeanDefinitionRegistry {
// 注册bean定义
void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException;
// 删除bean定义
void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 获取bean定义
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// 检查bean定义
boolean containsBeanDefinition(String beanName);
// 注册bean别名
void registerAlias(String name, String alias);
// 删除bean别名
void removeAlias(String alias);
// 检查bean别名
boolean isAlias(String name);
// 获取bean别名
String[] getAliases(String name);
}
来看看 GenericApplicationContext
如何实现这些接口的
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
@Override
public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
this.beanFactory.removeBeanDefinition(beanName);
}
@Override
public BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
return this.beanFactory.getBeanDefinition(beanName);
}
@Override
public void registerAlias(String beanName, String alias) {
this.beanFactory.registerAlias(beanName, alias);
}
@Override
public void removeAlias(String alias) {
this.beanFactory.removeAlias(alias);
}
@Override
public boolean isAlias(String beanName) {
return this.beanFactory.isAlias(beanName);
}
}
最终还是落脚在 beanFactory
上
GenericWebApplicationContext
的主要功能是添加了设置 bean 配置文件来源,允许通过配置的方式实例化上下文环境
public class GenericWebApplicationContext extends GenericApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource {}
ConfigurableWebApplicationContext
public interface ConfigurableWebApplicationContext {
// 设置bean配置文件来源
void setConfigLocation(String configLocation);
// 设置多个bean配置文件来源
void setConfigLocations(String... configLocations);
// 获取bean配置文件来源
String[] getConfigLocations();
}
ConfigurableWebApplicationContext
扩展了WebApplicationContext
,定义了允许通过配置的方式实例化上下文环境
public class GenericWebApplicationContext extends GenericApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource {
@Override
protected ConfigurableEnvironment createEnvironment() {
// StandardServletEnvironment扩展了StandardEnvironment
// 增加了可以从Servlet context init parameters和Servlet config init parameters增加应用配置来源
return new StandardServletEnvironment();
}
// 不可设置bean配置文件来源
@Override
public void setConfigLocation(String configLocation) {
if (StringUtils.hasText(configLocation)) {
throw new UnsupportedOperationException(
"GenericWebApplicationContext does not support setConfigLocation(). " +
"Do you still have an 'contextConfigLocations' init-param set?");
}
}
@Override
public void setConfigLocations(String... configLocations) {
if (!ObjectUtils.isEmpty(configLocations)) {
throw new UnsupportedOperationException(
"GenericWebApplicationContext does not support setConfigLocations(). " +
"Do you still have an 'contextConfigLocations' init-param set?");
}
}
@Override
public String[] getConfigLocations() {
throw new UnsupportedOperationException(
"GenericWebApplicationContext does not support getConfigLocations()");
}
}
GenericWebApplicationContext
并未实现 ConfigurableWebApplicationContext
的核心方法,也就不能通过文件加载配置,
该类设计的目的不是在web.xml
中进行声明式的安装,而是编程式的安装,例如使用WebApplicationInitializers
来构建内嵌的上下文;一般很少用到
因为 StaticApplicationContext
实现功能比较少,放在这里一起解析
public class StaticApplicationContext extends GenericApplicationContext {
private final StaticMessageSource staticMessageSource;
public StaticApplicationContext(@Nullable ApplicationContext parent) throws BeansException {
super(parent);
// 上下文对象中有一个messageSource组件,实现了i18n功能
// 而StaticMessageSource实现的是由程序载入文本,而非文件,便是去掉了i18n功能
this.staticMessageSource = new StaticMessageSource();
getBeanFactory().registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.staticMessageSource);
}
}
StaticWebApplicationContext
实现功能也比较少
public class StaticWebApplicationContext extends StaticApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource {
// 不可设置bean配置文件来源
@Override
public void setConfigLocation(String configLocation) {
throw new UnsupportedOperationException("StaticWebApplicationContext does not support config locations");
}
@Override
public void setConfigLocations(String... configLocations) {
throw new UnsupportedOperationException("StaticWebApplicationContext does not support config locations");
}
@Override
public String[] getConfigLocations() {
return null;
}
}
StaticWebApplicationContext
也并未实现 ConfigurableWebApplicationContext
的核心方法,也就不能通过文件加载配置,
该类设计的目的主要用于测试,不用于产品环境
AbstractRefreshableApplicationContext
的主要功能是创建 bean 工厂,刷新上下文数据
public abstract class AbstractRefreshableApplicationContext extends AbstractApplicationContext {
@Override
protected final void refreshBeanFactory() throws BeansException {
// ... 代码省略
try {
// 创建bean工厂
DefaultListableBeanFactory beanFactory = createBeanFactory();
// ... 代码省略
// 加载bean的定义
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
// 创建bean工厂
protected DefaultListableBeanFactory createBeanFactory() {
// 默认使用DefaultListableBeanFactory创建bean工厂
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
// 加载bean的定义,由子类实现
protected abstract void loadBeanDefinitions(DefaultListableBeanFactory beanFactory)
throws BeansException, IOException;
}
AbstractRefreshableConfigApplicationContext
的主要功能是可以通过文件加载配置
public abstract class AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext
implements BeanNameAware, InitializingBean {
// 设置配置文件来源,以",; \t\n"分隔多个
public void setConfigLocation(String location) {
setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));
}
public void setConfigLocations(@Nullable String... locations) {
if (locations != null) {
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
// 解析路径,替换${}占位符
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}
// 获取配置文件来源集,如果没有,则返回默认的
protected String[] getConfigLocations() {
return (this.configLocations != null ? this.configLocations : getDefaultConfigLocations());
}
// 默认的配置文件来源集由子类实现
protected String[] getDefaultConfigLocations() {
return null;
}
// 解析路径,替换${}占位符,有PropertySourcesPropertyResolver.resolveRequiredPlaceholders实现此功能
protected String resolvePath(String path) {
return getEnvironment().resolveRequiredPlaceholders(path);
}
}
AbstractRefreshableConfigApplicationContext
实现了 ConfigurableWebApplicationContext
的核心方法,也就是可以文件加载配置PropertySourcesPropertyResolver
如何是解析路径的,后面再解析因为 AbstractRefreshableWebApplicationContext
实现功能比较少,放在这里一起解析
public abstract class AbstractRefreshableWebApplicationContext extends AbstractRefreshableConfigApplicationContext
implements ConfigurableWebApplicationContext, ThemeSource {
@Override
protected ConfigurableEnvironment createEnvironment() {
// StandardServletEnvironment扩展了StandardEnvironment
// 增加了可以从Servlet context init parameters和Servlet config init parameters增加应用配置来源
return new StandardServletEnvironment();
}
}
XmlWebApplicationContext
的主要功能是定义了默认的配置文件,创建一个 bean 定义的 xml 解析器,并注册 bean 定义
public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {
// 默认配置文件
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";
// 默认配置文件前缀
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
// 默认配置文件后缀
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建一个bean定义的xml解析器,用XmlBeanDefinitionReader实现
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// ... 代码省略
// 载入bean定义
loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
// 通过配置文件载入bean定义
reader.loadBeanDefinitions(configLocation);
}
}
}
@Override
protected String[] getDefaultConfigLocations() {
if (getNamespace() != null) {
// 如果有servlet-name(如testapp),用前缀后缀包裹为"/WEB-INF/testapp-servlet.xml"
return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
}
else {
// 如果没有,默认为"/WEB-INF/applicationContext.xml"文件
return new String[] {DEFAULT_CONFIG_LOCATION};
}
}
}
XmlWebApplicationContext
主要解决了 2 个问题:
testapp
),用前缀后缀包裹为/WEB-INF/testapp-servlet.xml
,如果没有 servlet-name,则为/WEB-INF/applicationContext.xml
SpringMVC 框架的默认加载机制便是使用XmlWebApplicationContext
作为上下文环境,从 xml
文件加载配置与 bean 定义
至于XmlBeanDefinitionReader
如何是解析 bean 定义的,后面再解析
AnnotationConfigWebApplicationContext
的主要功能是可以通过注解载入配置和 bean 定义
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext
implements AnnotationConfigRegistry {}
public interface AnnotationConfigRegistry {
// 根据类名注册组件
void register(Class<?>... componentClasses);
// 根据包名扫描组件
void scan(String... basePackages);
}
这两个方法正好是通过注解如 @Configuration, @bean, @Component, @Controller, @Service
等注册 bean 的底层机制
来看看 AnnotationConfigWebApplicationContext
是如何实现的
public class AnnotationConfigWebApplicationContext extends AbstractRefreshableWebApplicationContext
implements AnnotationConfigRegistry {
// 组件类集合
private final Set<Class<?>> componentClasses = new LinkedHashSet<>();
// 扫描包名集合
private final Set<String> basePackages = new LinkedHashSet<>();
// 注册组件
@Override
public void register(Class<?>... componentClasses) {
Collections.addAll(this.componentClasses, componentClasses);
}
// 添加扫描包名
@Override
public void scan(String... basePackages) {
Collections.addAll(this.basePackages, basePackages);
}
// 加载bean定义
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) {
// 创建一个bean定义的注解解析器,用AnnotatedBeanDefinitionReader实现
AnnotatedBeanDefinitionReader reader = getAnnotatedBeanDefinitionReader(beanFactory);
// 创建一个基于包名的bean注解扫描器,用ClassPathBeanDefinitionScanner实现
ClassPathBeanDefinitionScanner scanner = getClassPathBeanDefinitionScanner(beanFactory);
// 创建一个bean命名生成器
BeanNameGenerator beanNameGenerator = getBeanNameGenerator();
if (beanNameGenerator != null) {
reader.setBeanNameGenerator(beanNameGenerator);
scanner.setBeanNameGenerator(beanNameGenerator);
beanFactory.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, beanNameGenerator);
}
// 创建一个bean作用域元信息解析器,判断注册的bean是原生类型(prototype)还是单例类型(singleton)
ScopeMetadataResolver scopeMetadataResolver = getScopeMetadataResolver();
if (scopeMetadataResolver != null) {
reader.setScopeMetadataResolver(scopeMetadataResolver);
scanner.setScopeMetadataResolver(scopeMetadataResolver);
}
// 注册组件类
if (!this.componentClasses.isEmpty()) {
reader.register(ClassUtils.toClassArray(this.componentClasses));
}
// 扫描包
if (!this.basePackages.isEmpty()) {
scanner.scan(StringUtils.toStringArray(this.basePackages));
}
// 通过定义的配置来源注册组件类或扫描包名
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
try {
Class<?> clazz = ClassUtils.forName(configLocation, getClassLoader());
reader.register(clazz);
}
catch (ClassNotFoundException ex) {
int count = scanner.scan(configLocation);
// ... 代码省略
}
}
}
}
// 创建一个bean定义的注解解析器,用AnnotatedBeanDefinitionReader实现
protected AnnotatedBeanDefinitionReader getAnnotatedBeanDefinitionReader(DefaultListableBeanFactory beanFactory) {
return new AnnotatedBeanDefinitionReader(beanFactory, getEnvironment());
}
// 创建一个基于包名的bean注解扫描器,用ClassPathBeanDefinitionScanner实现
protected ClassPathBeanDefinitionScanner getClassPathBeanDefinitionScanner(DefaultListableBeanFactory beanFactory) {
return new ClassPathBeanDefinitionScanner(beanFactory, true, getEnvironment());
}
}
实际上,注册 bean 是由AnnotatedBeanDefinitionReader
完成,扫描包是由ClassPathBeanDefinitionScanner
完成,这两个类后面再解析
GroovyWebApplicationContext
的运行机制与 XmlWebApplicationContext
差不多,从 groovy
文件加载配置与 bean 定义
public class GroovyWebApplicationContext extends AbstractRefreshableWebApplicationContext implements GroovyObject {
// 默认配置文件
public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.groovy";
// 默认配置文件前缀
public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";
// 默认配置文件后缀
public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".groovy";
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建一个bean定义的Groovy解析器,用GroovyBeanDefinitionReader实现
GroovyBeanDefinitionReader beanDefinitionReader = new GroovyBeanDefinitionReader(beanFactory);
// ... 代码省略
// 载入bean定义
loadBeanDefinitions(beanDefinitionReader);
}
protected void loadBeanDefinitions(GroovyBeanDefinitionReader reader) throws IOException {
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
// 通过配置文件载入bean定义
reader.loadBeanDefinitions(configLocation);
}
}
}
@Override
protected String[] getDefaultConfigLocations() {
if (getNamespace() != null) {
// 如果有servlet-name(如testapp),用前缀后缀包裹为"/WEB-INF/testapp-servlet.groovy"
return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};
}
else {
// 如果没有,默认为"/WEB-INF/applicationContext.groovy"文件
return new String[] {DEFAULT_CONFIG_LOCATION};
}
}
}
WebApplicationContext
定义了 Web 应用初始化的基本流程,主要有 5 个实现类,常用的是:基于 Xml 加载的XmlWebApplicationContext
与基于注解加载的AnnotationConfigWebApplicationContext
WebApplicationContext
的基础实现,都不能通过配置文件和注解加载应用配置与 bean,一般用于扩展实现(如 SpringBoot),很少直接使用@Configuration, @bean
等加载应用配置与 bean 的上下文环境XmlWebApplicationContext
的实现差不多,但可以用 Groovy 代替 xml 做配置文件,但目前 Groovy 远不及 Xml 普及,用的仍然不多这一节仍然有一些点留待下次解析:
ConfigurableListableBeanFactory
如何加载、实例化 beanResourceEditorRegistrar
如何注册属性编辑器、属性编辑器如何解析为对象PathMatchingResourcePatternResolver
如何解析、加载 locationPattern 指定的资源PropertySourcesPropertyResolver
如何是解析路径的XmlBeanDefinitionReader
如何是解析 bean 定义的AnnotatedBeanDefinitionReader
是如何注册 bean 的ClassPathBeanDefinitionScanner
是如何扫描包的更多博客,查看 https://github.com/senntyou/blogs
版权声明:自由转载-非商用-非衍生-保持署名(创意共享 3.0 许可证)
我尝试阅读有关 Spring BOM、Spring Boot 和 Spring IO 的文档。 但是没有说明,我们应该如何一起使用它们? 在我的项目中,我们已经有了自己的 Parent POM ,所以
我正在开发的很酷的企业应用程序正在转向 Spring。这对所有团队来说都是非常酷和令人兴奋的练习,但也是一个巨大的压力源。我们所做的是逐渐将遗留组件移至 Spring 上下文。现在我们有一个 huuu
我正在尝试使用 @Scheduled 运行 Spring 批处理作业注释如下: @Scheduled(cron = "* * * * * ?") public void launchMessageDi
我对这两个概念有点困惑。阅读 Spring 文档,我发现,例如。 bean 工厂是 Spring 容器。我还读到“ApplicationContext 是 BeanFactory 的完整超集”。但两者
我们有一个使用 Spring BlazeDS 集成的应用程序。到目前为止,我们一直在使用 Spring 和 Flex,它运行良好。我们现在还需要添加一些 Spring MVC Controller 。
假设我有一个类(class) Person带属性name和 age ,它可以像这样用 Spring 配置: 我想要一个自定义的 Spring 模式元素,这很容易做到,允许我在我的 Sp
如何在 Java 中以编程方式使用 Spring Data 创建 MongoDB 复合索引? 使用 MongoTemplate 我可以创建一个这样的索引:mongoTemplate.indexOps(
我想使用 spring-complex-task 执行我的应用程序,并且我已经构建了复杂的 spring-batch Flow Jobs,它执行得非常好。 你能解释一下spring批处理流作业与spr
我实现了 spring-boot 应用程序,现在我想将它用作非 spring 应用程序的库。 如何初始化 lib 类,以便 Autowiring 的依赖项按预期工作?显然,如果我使用“new”创建类实
我刚开始学习 spring cloud security,我有一个基本问题。它与 Spring Security 有何不同?我们是否需要在 spring boot 上构建我们的应用程序才能使用 spr
有很多人建议我使用 Spring Boot 而不是 Spring 来开发 REST Web 服务。我想知道这两者到底有什么区别? 最佳答案 总之 Spring Boot 减少了编写大量配置和样板代码的
您能向我解释一下如何使用 Spring 正确构建 Web 应用程序吗?我知道 Spring 框架的最新版本是 4.0.0.RELEASE,但是 Spring Security 的最新版本是 3.2.0
我如何才能知道作为 Spring Boot 应用程序的一部分加载的所有 bean 的名称?我想在 main 方法中有一些代码来打印服务器启动后加载的 bean 的详细信息。 最佳答案 如spring-
我有一个使用 Spring 3.1 构建的 RESTful API,也使用 Spring Security。我有一个 Web 应用程序,也是一个 Spring 3.1 MVC 应用程序。我计划让移动客
升级到 Spring 5 后,我在 Spring Rabbit 和 Spring AMQP 中遇到错误。 两者现在都设置为 1.5.6.RELEASE 有谁知道哪些版本应该与 Spring 5 兼容?
我现在已经使用 Spring Framework 3.0.5 和 Spring Security 3.0.5 多次了。我知道Spring框架使用DI和AOP。我还知道 Spring Security
我收到错误 Unable to Location NamespaceHandler when using context:annotation-config running (java -jar) 由
在 Spring 应用程序中嵌入唯一版本号的策略是什么? 我有一个使用 Spring Boot 和 Spring Web 的应用程序。 它已经足够成熟,我想对其进行版本控制并在运行时看到它显示在屏幕上
我正在使用 spring data jpa 进行持久化。如果存在多个具有相同名称的实体,是否有一种方法可以将一个实体标记为默认值。类似@Primary注解的东西用来解决多个bean的依赖问题 @Ent
我阅读了 Spring 框架的 DAOSupport 类。但是我无法理解这些 DAOSuport 类的优点。在 DAOSupport 类中,我们调用 getXXXTemplate() 方法来获取特定的
我是一名优秀的程序员,十分优秀!