Spring Framework
- 发布于2002年10月1日
强大的基于 JavaBeans 的采用控制反转(Inversion of Control,IoC)原则的配置管理,使得应用程序的组建更加简易快捷。
数据库事务的一般化抽象层,允许声明式(Declarative)事务管理器,简化事务的划分使之与底层无关。
内建的针对 JTA 和单个 JDBC 数据源的一般化策略,使Spring的事务支持不要求 Java EE 环境,这与一般的 JTA 或者 EJB CMT 相反。
JDBC 抽象层提供了有针对性的异常等级(不再从 SQL 异常中提取原始代码),简化了错误处理,大大减少了程序员的编码量。再次利用 JDBC 时,你无需再写出另一个'终止'(finally)模块。并且面向 JDBC 的异常与 Spring 通用数据访问对象(Data Access Object)异常等级相一致。
以资源容器,DAO 实现和事务策略等形式与 Hibernate,JDO 和 MyBatis 、SQL Maps 集成。利用控制反转机制全面解决了许多典型的 Hibernate 集成问题。所有这些全部遵从 Spring 通用事务处理和通用数据访问对象异常等级规范。
灵活的基于核心 Spring 功能的 MVC 网页应用程序框架。开发者通过策略接口将拥有对该框架的高度控制,因而该框架将适应于多种呈现(View)技术,例如 JSP、FreeMarker、Velocity、Thymeleaf 等。值得注意的是,Spring 中间层可以轻易地结合于任何基于 MVC 框架的网页层,例如 Struts、WebWork 或 Tapestry。
提供诸如事务管理等服务的AOP框架。
在设计应用程序 Model 时,MVC模式(例如 Struts)通常难于给出一个简洁明了的框架结构。Spring 却具有能够让这部分工作变得简单的能力。程序开发员们可以使用Spring的JDBC抽象层重新设计那些复杂的框架结构。
上述是维基百科给出的Spring核心功能模块定义,我们可以看出Spring做了什么有哪些用处。Spring是一个BeanFactory,负责加载Bean和管理Bean的生命周期与依赖关系这也就是IOC控制反转,它还支持AOP以便支持切面编程,Spring MVC给出了一个简单的MVC模式范例很方便的支持日常用到的贫血模型,以及Spring Boot可以支持简化配置。
BeanFactory
既然知道了Spring中IOC的核心组件时BeanFactory,那么我们来了解一下什么是BeanFactory。见词晓意一个组件工厂,用来生产组件和获得组件。
public interface BeanFactory {
//用&MyFactory获得工厂,&为表示工厂的前缀
String FACTORY_BEAN_PREFIX = "&";
//通过名字或别名获取Bean
Object getBean(String name) throws BeansException;
//获取时要匹配类型requiredType需要是超类或者继承的接口
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
//args使用显示参数创建Bean时需要用到的参数
Object getBean(String name, Object... args) throws BeansException;
//通过类型获取Bean
<T> T getBean(Class<T> requiredType) throws BeansException;
//类型和参数
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
//返回一个Bean提供程序允许检测可用性和唯一性支持懒加载,就是一个ObjectFactory
<T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
//根据name查找是否含有Bean定义和单例Bean,如果是分层的工厂则查找超类
boolean containsBean(String name);
//是否是单例的们也会递归查找 PS:单例是每次调用都可以返回相同实例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
//Spring支持的原型类型也就是每次调用都返回一个新的实例
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
//检查是否可以返回一个给定意义的对象,ResolvableType中定义了类型
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
//Class版本的type
boolean isTypeMatch(String name, Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
//拿到类型,对于FactoryBean返回工厂生产的Bean实例类型,默认会初始化工厂
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
//allow询问要不要初始化工厂
Class<?> getType(String name, boolean allowFactoryBeanInit) throws NoSuchBeanDefinitionException;
//返回别名,原始名称为数组中的第一个元素
String[] getAliases(String name);
上述就是BeanFactory全部方法,先是一些重载的getBean各种类型如用name获取,或者用requiredType获取再是获取ObjectProvider再者是检测有没有这个Bean,Bean的类型与生成规则,最后是拿到这个Bean的Type与别名。可以看出这个工厂是Spring最核心的组件。
什么是耦合呢?为什么使用new会造成耦合?
//一句简单的泛型,接口持有子类引用
ProfileService profileService = new ProfileServiceImpl();
上述代码为题在哪里呢?其实也没啥问题,如果是写个小项目完全没有任何问题有时候我们需要替换Impl时直接Ctrl+F定位Impl然后正则替换!完结撒花,Spring结束!
开个玩笑,假设项目中有很多中这样的impl很常见的,我们在替换时需要替换每一个地方的,但是有些地方有没有什么可以快速替换的方式呢?有的
(XXXImpl)BeanFactroy.getBean(XXX);
好处时什么呢?我们可以直接在Bean工厂中替换Impl实现,如我们采用注解的方式实现一个接口,在实现类Impl上标明采用这个实现类,如果下一次想换一个那么把这个注解移到另一个类就可以,这样子对代码中侵入性修改就可以降低到最小。
ApplicationContext 应用上下文
从上图中,我们可以很明显看出Application继承自BeanFactory,Listable是可以一次获取多个Bean,BeanFactory的方法中都是获取单个,Hierarchical,可以有继承关系的BeanFactory。应用程序中常见的两个Appcontext有ClassPathXmlApplicationContext,AnnotationConfigApplicationContext
上述最要中的观察点已经标识,程序中两种最重要的上下文可以采用注解和Xml两种形式,ApplicationContext启动过程中会负责创建Bean与Bean的依赖注入。
分析ApplicationContext的启动过程
我们从ClassPathXmlApplicationContext的源码中分析context的启动过程,进入源码中发现只有200多行美滋滋。
public class ClassPathXmlApplicationContext extends AbstractXmlApplicationContext {
@Nullable
private Resource[] configResources;
public ClassPathXmlApplicationContext(ApplicationContext parent) {
super(parent);
}
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
super(parent);
//处理配置文件数组
setConfigLocations(configLocations);
if (refresh) {
//核心方法刷新
refresh();
}
}
1.setConfigLocations
setConfigLocations是超类AbstractRefreshableConfigApplicationContext中的方法用于解析配置文件路径,处理成配置文件数组。也就是一个String[]configLocations,先判断下非空再对Path进行trim去除空白符再resolvePath进行解析。
2.refresh()
这个方法也是由超类实现的值得一提的是为什么叫refresh而不是init那因为可以重新调用这个方法来进行销毁重建,具体代码如下
public void refresh() throws BeansException, IllegalStateException {
// 加锁以防止refresh没结束又进行一个刷新
synchronized (this.startupShutdownMonitor) {
// 准备上下文用于刷新
prepareRefresh();
// 刷新内部Bean工厂,解析配置文件生成Bean定义注册到BeanFactory
// 没有进行初始化Bean
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 设置BeanFactory的类加载器 添加几个BeanPostProcessor手动注册一些单例Bean
prepareBeanFactory(beanFactory);
try {
// 扩展点,如果类实现了这个这个方法可以再容器初始化后做些什么
postProcessBeanFactory(beanFactory);
// 调用processors
invokeBeanFactoryPostProcessors(beanFactory);
// 注册BeanPostProcessors
// 如果Bean实现了接口的两个方法postProcessBeforeInitialization和postProcessAfterInitialization
//那么在Bean初始化的过程之前和之后会进行调用
registerBeanPostProcessors(beanFactory);
// 初始化当前context的信息源
initMessageSource();
// 初始化时间广播器
initApplicationEventMulticaster();
// 初始化一些特殊的Bean
onRefresh();
// 注册事件监听器
registerListeners();
// 初始化所有单例懒加载的除外
finishBeanFactoryInitialization(beanFactory);
// 最后一步广播初始化完成事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 发生异常则销毁创建的单例
destroyBeans();
// 重置active标志位为false
cancelRefresh(ex);
// 异常抛出去
throw ex;
}
finally {
//设置内省缓存,可能不在需要单例的元数据
resetCommonCaches();
}
}
}
这个refresh内容蛮多的,具体概括一下就是刷新一下BeanFactory加载新的Bean定义再初始化一些特殊Bean与注册事件监听器初始化单例,消除单例Bean的元数据,下面我们简单分析一下每个调用语句。
创建BeanFactory之前的准备工作
protected void prepareRefresh() {
// 设置启动时间与标志位
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
}
else {
logger.debug("Refreshing " + getDisplayName());
}
}
// 初始化占位符属性源
initPropertySources();
// 校验标记文件是否可以解析
getEnvironment().validateRequiredProperties();
// 存储earlyApplicationListeners到applicationListeners,并新建一个
// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
}
else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}
// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<>();
}
创建Bean容器,加载Bean并注册
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//刷新BeanFactroy如果有旧的就关闭再创建个新的
//加载Bean定义与注册Bean
refreshBeanFactory();
//返回新的beanFactory
return getBeanFactory();
}
//在AbstractRefreshableApplicationContext有这个方法的实现
protected final void refreshBeanFactory() throws BeansException {
//如果加载过BeanFactory就销毁掉所有Bean并关闭BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建一个DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
//设置序列化ID
beanFactory.setSerializationId(getId());
// 定制一下BeanFactory允许Bean的覆盖与循环引用
customizeBeanFactory(beanFactory);
// 加载Bean定义
loadBeanDefinitions(beanFactory);
//设置beanFactory
this.beanFactory = beanFactory;
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
方法很简单主要是为什么BeanFactory要使用DefaultListableBeanFactory,这个类继承了所有实现,被设计成一个默认的BeanFactory
loadBeanDefinitions加载BeanDefinition
什么是BeanDefinition?Bean的定义保存了Bean的元信息指向哪个类,是否是单例要不要懒加载Bean依赖于哪些Bean
BeanDefinition定义
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
//默认提供两种类型单例与原型
String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
//Bean的角色
int ROLE_APPLICATION = 0;
int ROLE_SUPPORT = 1;
int ROLE_INFRASTRUCTURE = 2;
// Modifiable attributes
//设置父Bean也就是继承父Bean的配置信息
void setParentName(@Nullable String parentName);
// 获取父Bean
@Nullable
String getParentName();
// 设置Bean的类名
void setBeanClassName(@Nullable String beanClassName);
// 获取Bean的类名
@Nullable
String getBeanClassName();
// 设置作用域
void setScope(@Nullable String scope);
// 获取作用域
@Nullable
String getScope();
// 设置懒加载
void setLazyInit(boolean lazyInit);
boolean isLazyInit();
// 设置依赖的Bean 重点BeanFactory可以保证这些依赖的Bean可以在他前面初始化
void setDependsOn(@Nullable String... dependsOn);
// 返回依赖Bean名称
@Nullable
String[] getDependsOn();
// 设置是否可以注入到其他Bean只影响类型注入
// 显示的名称注入依然有效
void setAutowireCandidate(boolean autowireCandidate);
boolean isAutowireCandidate();
// 设置Primary 同一个接口多个实现不指定名称会选择主要那个
void setPrimary(boolean primary);
boolean isPrimary();
// 如果是工厂模式生产的就设置一下工厂
void setFactoryBeanName(@Nullable String factoryBeanName);
@Nullable
String getFactoryBeanName();
// 用哪个工厂方法
void setFactoryMethodName(@Nullable String factoryMethodName);
@Nullable
String getFactoryMethodName();
// 构造器参数值
ConstructorArgumentValues getConstructorArgumentValues();
// 构造器是否是有参的
default boolean hasConstructorArgumentValues() {
return !getConstructorArgumentValues().isEmpty();
}
// Bean中的属性值
MutablePropertyValues getPropertyValues();
default boolean hasPropertyValues() {
return !getPropertyValues().isEmpty();
}
// 设置初始化方法名称
void setInitMethodName(@Nullable String initMethodName);
@Nullable
String getInitMethodName();
// 设置销毁方法名称
void setDestroyMethodName(@Nullable String destroyMethodName);
@Nullable
String getDestroyMethodName();
// 设置角色
void setRole(int role);
int getRole();
// 提供人可以读的描述
void setDescription(@Nullable String description);
@Nullable
String getDescription();
// 只读属性
// 返回可解析类型
ResolvableType getResolvableType();
boolean isSingleton();
boolean isPrototype();
boolean isAbstract();
@Nullable
String getResourceDescription();
@Nullable
BeanDefinition getOriginatingBeanDefinition();
}
定义了Bean的作用域,构造器,Bean生成规则,初始化和销毁方法
回到refreshBeanFactory() 中剩下还有两个重要方法
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
//是否允许Bean定义覆盖
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
//是否允许循环依赖
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}
Spring的默认值是同一配置文件不允许覆盖,不同则可以。而默认情况下Spring允许循环依赖,构造方法的循环依赖不允许
加载BeanDefinition
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 实例化一个XmlBeanDefinitionReader
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 允许子类提供BeanDefinitionReader的自定义初始化
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}
loadBeanDefinitions 很重要的方法用是初始化的Reader开始加载Bean定义
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 使用其他重载的方法以进行加载
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}
public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int count = 0;
// 简单的遍历加载然后返回加载个数
for (Resource resource : resources) {
count += loadBeanDefinitions(resource);
}
return count;
}
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isTraceEnabled()) {
logger.trace("Loading XML bean definitions from " + encodedResource);
}
// 用ThreadLocal来存放配置文件资源
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try (InputStream inputStream = encodedResource.getResource().getInputStream()) {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//核心加载方法
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//XML转DOM
Document doc = doLoadDocument(inputSource, resource);
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}
// 具体的parse解析方法有很多种实现,这里不展开了如果学了编译原理应该无压力
public void parse(XMLInputSource source) throws XNIException, IOException {
if (fParseInProgress) {
// REVISIT - need to add new error message
throw new XNIException("FWK005 parse may not be called while parsing.");
}
fParseInProgress = true;
try {
setInputSource(source);
parse(true);
} catch (XNIException ex) {
if (PRINT_EXCEPTION_STACK_TRACE)
ex.printStackTrace();
throw ex;
} catch (IOException ex) {
if (PRINT_EXCEPTION_STACK_TRACE)
ex.printStackTrace();
throw ex;
} catch (RuntimeException ex) {
if (PRINT_EXCEPTION_STACK_TRACE)
ex.printStackTrace();
throw ex;
} catch (Exception ex) {
if (PRINT_EXCEPTION_STACK_TRACE)
ex.printStackTrace();
throw new XNIException(ex);
} finally {
fParseInProgress = false;
// close all streams opened by xerces
this.cleanup();
}
}
public boolean parse(boolean complete) throws XNIException, IOException {
//
// reset and configure pipeline and set InputSource.
if (fInputSource != null) {
try {
fValidationManager.reset();
fVersionDetector.reset(this);
fConfigUpdated = true;
resetSymbolTable();
resetCommon();
short version = fVersionDetector.determineDocVersion(fInputSource);
if (version == Constants.XML_VERSION_1_1) {
initXML11Components();
configureXML11Pipeline();
resetXML11();
} else {
configurePipeline();
reset();
}
// mark configuration as fixed
fConfigUpdated = false;
// resets and sets the pipeline.
fVersionDetector.startDocumentParsing((XMLEntityHandler) fCurrentScanner, version);
fInputSource = null;
} catch (IOException | RuntimeException ex) {
if (PRINT_EXCEPTION_STACK_TRACE)
ex.printStackTrace();
throw ex;
} catch (Exception ex) {
if (PRINT_EXCEPTION_STACK_TRACE)
ex.printStackTrace();
throw new XNIException(ex);
}
}
try {
return fCurrentScanner.scanDocument(complete);
} catch (IOException | RuntimeException ex) {
if (PRINT_EXCEPTION_STACK_TRACE)
ex.printStackTrace();
throw ex;
} catch (Exception ex) {
if (PRINT_EXCEPTION_STACK_TRACE)
ex.printStackTrace();
throw new XNIException(ex);
}
}
经过如上的漫长方法,可以把配置文件转换成DOM树上面仅仅是转换成DOM树下面介绍下解析DOM树
DefaultBeanDefinitionDocumentReader
protected void doRegisterBeanDefinitions(Element root) {
// 方法可以递归调用 在parseDefaultElement中调用了doRegisterBeanDefinitions
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
//判断一下是否是根节点
//URL里是否含有BEANS_NAMESPACE_URI
if (this.delegate.isDefaultNamespace(root)) {
// 读取beans的profile
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
//按照 ,;对profileSpec差分
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
// We cannot use Profiles.of(...) since profile expressions are not supported
// in XML config. See SPR-12458 for details.
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isDebugEnabled()) {
logger.debug("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
//钩子函数
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
// 解析文档中 import alias bean等元素
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if (delegate.isDefaultNamespace(ele)) {
//解析Default
parseDefaultElement(ele, delegate);
}
else {
//解析定制的
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
public boolean isDefaultNamespace(@Nullable String namespaceUri) {
return (!StringUtils.hasLength(namespaceUri) || BEANS_NAMESPACE_URI.equals(namespaceUri));
}
/**
* Determine whether the given node indicates the default namespace.
*/
public boolean isDefaultNamespace(Node node) {
return isDefaultNamespace(getNamespaceURI(node));
}
public static final String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";
可以看出默认的Namespace也就是要测试namespaceUri是否是BEANS_NAMESPACE_URI
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire="byName" >
上述为一段典型的xml定义,上面有就使用到BEANS_NAMESPACE_URI,也就是解析XML中的各个节点,常见的有import,bean,aop,context,mvc,区别在于BEANS_NAMESPACE_URI中定义的是默认的其他的是定制的。
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//解析<import/>
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//解析<alias/>
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//解析<bean/>
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//解析<nested/>
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}
对importBeanDefinitionResource进行一个浅析,读取一下元素再查看一下import里面有没有resuouce然后对引入资源进行加载
<import resource = "xxxxx.xml">
public static final String RESOURCE_ATTRIBUTE = "resource";
//简述
protected void importBeanDefinitionResource(Element ele) {
String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
if (!StringUtils.hasText(location)) {
getReaderContext().error("Resource location must not be empty", ele);
return;
}
-----省略
}
总结
对今天的BeanFactory解析进行一个总结,我们深入探讨了BeanFactory的模型与ApplicationContext,知道了上下文的refresh方法用于生成Bean定义与销毁重加载BeanFactory,对BeanDefinition进行了深入了解和解析XML文件,最后分析了一下XML文件生成的DOM树如何解析并对一些简单的如<import resuource = "">
进行了浅显的解析已推出XML文件的解析大致流程。
今天时间有限先对Spring框架做一个大致了解,知道什么是BeanFactory和ApplicationContext即可。朋友们走过路过不要忘记点赞,你的点赞是我更新的动力。