由ResourceLoader通过Resource接口定位资源,Resouce接口有如下实现,通过名字就能猜到大概都能通过哪些方式定位资源
图片.png
FileSystemXmlApplicationContext通过继承DefaultResourceLoader具备了定位Resouce功能,下面这张继承关系图非常重要
图片.png
DefaultResourceLoader实现了ResourceLoader接口
图片.png
refresh()载入了BeanDefiniation,会在载入章节详细说明
图片.png
应用于文件系统的Resource实现,在BeanDefiniationReader.loadBeanDefination()中被调用loadBeanDefination()采用了模板方法,具体Resource定位方式由子类决定,在org.springframework.core.io.DefaultResourceLoader中被调用
图片.png
创建DefaultListableBeanFactory和加载配置文件在org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory()完成
图片.png
分析一下是如何调用到AbstractRefreshableApplicationContext.refreshBeanFactory()呢,FileSystemXmlApplicationContext在构造中调用了refresh(),refresh()在org.springframework.context.support.AbstractApplicationContext被调用
图片.png
refresh()中有一个重要的方法obtainFreshBeanFactory(),调用到org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory()
图片.png
在回到org.springframework.context.support.AbstractRefreshableApplicationContext.refreshBeanFactory()中(回看前面的FileSystemXmlApplicationContext结成结构,对于下面的调用理解很重要),createBeanFactory()创建了DefaultListableBeanFactory,这是一个默认的IoC实现
图片.png
org.springframework.context.support.AbstractXmlApplicationContext.loadBeanDefinitions(DefaultListableBeanFactory)中装载BeanDefination
图片.png
具体的解析过程在org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(String, Set
public int loadBeanDefinitions(String location, Set actualResources) throws BeanDefinitionStoreException {
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException(
"Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
//对Resource路径进行解析,如Ant风格路径
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// 在子类中调用refreshBeanFactory()
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
//设置BeanFacotry后置处理
postProcessBeanFactory(beanFactory);
//调用BeanFactory后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册Bean后置处理器,在Bean创建过程中调用
registerBeanPostProcessors(beanFactory);
// 初始化上小文消息
initMessageSource();
// 初始化上下文事件
initApplicationEventMulticaster();
// 初始化特殊bean
onRefresh();
// 注册Bean监听器
registerListeners();
// 实例化单例bean
finishBeanFactoryInitialization(beanFactory);
// 结束容器初始化,发布容器事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已经创建的单例bean
destroyBeans();
// 重置标志位
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
上节中已经看到过是如何加载BeanDefiniation了,FileSystemXmlApplicationContext默认使用的IoC容器是DefaultListableBeanFactory
图片.png
配置文件读取在org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(InputSource, Resource)中,registerBeanDefinitions()对BeanDefinitation解析过程,也就是Spring配置文件中配置Bean的规则
图片.png
BeanDefiniation载入过程分为两部分,首先创建XML的解析器document,在按照Spring配置文件规则解析,具体的解析过程在org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(Document, XmlReaderContext)中,
图片.png
org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element, BeanDefinitionParserDelegate)中想IoC容器注册BeanDefiniation,BeanDefinitionHolder封装了BeanDefiniation,增加了bean的名字和别名,bean的解析在BeanDefinitionParserDelegate完成,解析过程十分繁琐,参考Spring配置文件的配置规则
图片.png
经过Resource定位,和BeanDefiniation的载入和解析,BeanDefiniation已经在IoC容器中了,但还不能使用,需要向IoC容器注册,在DefaultListableBeanFactory中通过一个Map维护这些BeanDefiniation
图片.png
@Override
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException {
Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null");
if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
}
BeanDefinition oldBeanDefinition;
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
//如果出现beanName相同的情况,抛异常
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
"': There is already [" + oldBeanDefinition + "] bound.");
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
oldBeanDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + oldBeanDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List updatedDefinitions = new ArrayList(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set updatedSingletons = new LinkedHashSet(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}
if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}
spring容器和装配Bean:
1、容器是spring的核心,使IoC管理所有和组件
2、spring的两种容器:a、BeanFactoy
b、ApplicationContext应用上下文
3、BeanFactory:BeanhFactory使用延迟加载所有的Bean,为了从BeanhFactory得到一个Bean,只要调用
getBean()方法,就能获得Bean
4、ApplicationContext:a、提供文本信息解析,支持I18N
b、提供载入文件资源的通用方法
c、向注册为监听器的Bean发送事件
d、ApplicationContext接口扩展BeanFactory接口
e、ApplicationContext提供附加功能
5、ApplicationContext的三个实现类:a、ClassPathXmlApplication:把上下文文件当成类路径资源
b、FileSystemXmlApplication:从文件系统中的XML文件载入上
下文定义信息
c、XmlWebApplicationContext:从Web系统中的XML文件载入上下
文定义信息
6、在默认情况下,Bean全都是单态,在
7、
8、Bean的实例化的时候需要一些初始化的动作,同样当不再使用的时候,需要从容器中将其销毁
9、对象的初始化:
10、对象的销毁:
销毁对象的过程:a、主线程先被中断
b、Java虚拟机使用垃圾回收机制回收Bean对象
11、Bean设置:设值注入:1)简单配置:
value中的值可以是基本数据类型或者String类型,spring将会
自动判断设置的类型并且
将其转换成合适的值
2)引用配置:
ref中的值是引用数据类型,spring容器会完成获取工作
3)List和数组:
list元素内可以是任何元素,但不能违背Bean所需要的对象类
型
4)Set配置:和一样,将
改成
5)Map配置:Map中的每条数据是由一个键和一个值组成,用
义
注意:配置entry时,属性key的值只能是String,因为Map通常用
String作为主键
6)Properties配置:使用
String
注意:使用设值注入必须要有set方法,通过name属性找set方法
优势:a、通过set()方法设定更直观,更自然
b、当依赖关系较复杂时,使用set()方法更清晰
构造子注入:必须要有无参和带参的构造方法,加上index(值从0开始)属性避免注入混
淆
注意:设值注入可以和构造子注入混合使用。先调用构造方法产生对象,再调用set()方法
赋值。但只使用设值注入时,会先调用无参的构造方法
优势:a、依赖关系一次性设定,对外不准修改
b、无需关心方式
c、注入有先后顺序,防止注入失败