目录
注解和xml配置文件的理解
spring IOC启动过程
依赖注入
1、小马哥源码解读Spring IOC原理
2、Spring BeanDefinition 生成所有bean的配置信息
3、Spring依赖注入源码分析
容器启动时,先读取配置文件,如果发现配置文件里设置了扫描注解,则扫描注解生成每个bean的BeanDefinition放入BeanDefinition 容器。再继续读取xml,将配置的bean放入到BeanDefinition 容器中,这样bean定义容器就有了所有的BeanDefinition。
下一步就根据这些bean定义生成bean对象,并注入依赖的bean,如果依赖的bean没有,则继续生成,这样递归下去,知道所有的bean都生成结束。
构造一个IOC容器需要如下几个步骤:
第一步:资源的定位。所谓资源就是指Spring里众多的XML配置文件,要获取到配置文件里面的信息,首先是要找到它。
第二步:加载和解析资源文件。XML文件里面定义的一些节点,和Spring里面定义的数据结构不匹配,那么就需要按照Spring的解析规则将XML解析成Spring需要的。xml-->Document对象 -- >spring-bean规则定义的BeanDefinition
第三步:将解析完的数据结构注册到IOC容器中。Spring中内部的数据结构叫BeanDefinition。
经过以上三个步骤之后,IOC容器已经构造好,但是还是不能被直接使用。BeanDefinition只是配置文件里的配置在IOC中建立的一个映射,对于IOC容器来说最重要的依赖关系都还没有注入呢,相当于光有一个壳,内容还没有填充。
这里又有个Spring中重要的概念,叫做依赖注入。依赖的意思上文中有提到过吧,就是对象的引用关系嘛,注入是个动词,个人理解为设置,那依赖注入的意思不就是设置对象的引用关系了哇。
接下来这个过程是容器的实例化。容器的实例化只有一步,就是依赖注入。
完成IOC容器的构造和实例化之后,完整的IOC就建立好了。主线分析好了,接下来便可以顺藤摸瓜的学习源码了。
// IoC容器启动过程简析
public void TestDefaultListableBeanFactory(){
// 获取资源
ClassPathResource resource = new ClassPathResource("spring.xml");
// 创建IoC容器
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
// 资源读取器
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
// 资源读取器解析资源文件 解析为BeanDefinition
reader.loadBeanDefinitions(resource);
MyBean bean = factory.getBean(MyBean.class);
System.out.println(bean.toString());
}
// 定位:获取xml位置
// XmlWebApplicationContext
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
reader.loadBeanDefinitions(configLocation);
}
}
}
/*
加载解析:DefaultDocumentLoader 将xml解析为Document对象
载入Bean定义资源文件的最后一步是将Bean定义资源转换为Document对象,该过程由documentLoader实现
至此Spring IoC容器根据定位的Bean定义资源文件,将其加载读入并转换成为Document对象过程完成。
*/
// XmlBeanDefinitionReader
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 将xml解析为Document对象
Document doc = doLoadDocument(inputSource, resource);
// 这里是启动对Bean定义解析的详细过程,该解析过程会用到Spring的Bean配置规则
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
}
/*
Bean定义资源的载入解析分为以下两个过程:
首先,通过调用XML解析器将Bean定义资源文件转换得到Document对象,但是这些Document对象并没有按照Spring的Bean规则进行解析。这一步是载入的过程
其次,在完成通用的XML解析之后,按照Spring的Bean规则对Document对象进行解析。
按照Spring的Bean规则对Document对象解析的过程是在接口BeanDefinitionDocumentReader的实现类DefaultBeanDefinitionDocumentReader中实现的。
*/
/*
DefaultBeanDefinitionDocumentReader 默认的BeanDefinition文档读取类
*/
protected void doRegisterBeanDefinitions(Element root) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
Assert.state(this.environment != null, "Environment must be set for evaluating profiles");
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
return;
}
}
// Any nested elements will cause recursion in this method. In
// order to propagate and preserve default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(this.readerContext, root, parent);
// 解析前置操作
preProcessXml(root);
//使用Spring的Bean规则从Document的根元素开始进行Bean定义的Document对象
parseBeanDefinitions(root, this.delegate);
// 解析后置操作
postProcessXml(root);
this.delegate = parent;
}
/**
* 处理BeanDefinition
1、解析bean,将xml中解析未BeanDefinition 封装到BeanDefinitionHolder中:return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
2、注册BeanDefinition到IoC容器当中
*/
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
// 12、BeanDefinition解析代理解析Bean定义资源文件中的元素
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 在其parseDefaultElement方法中完成对Document对象的解析后得到封装BeanDefinition的BeanDefinitionHold对象,
// 然后调用BeanDefinitionReaderUtils的registerBeanDefinition方法向IoC容器注册解析的Bean,
// BeanDefinitionReaderUtils的注册的源码如下:
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}
// 12、BeanDefinitionParserDelegate 代理解析Bean定义资源文件中的元素
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
List aliases = new ArrayList();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}
// 在其parseDefaultElement方法中完成对Document对象的解析后得到封装BeanDefinition的BeanDefinitionHold对象,
// 然后调用BeanDefinitionReaderUtils的registerBeanDefinition方法向IoC容器注册解析的Bean,
// BeanDefinitionReaderUtils的注册的源码如下:
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// Register bean definition under primary name.
String beanName = definitionHolder.getBeanName();
// 当调用BeanDefinitionReaderUtils向IoC容器注册解析的BeanDefinition时,真正完成注册功能的是DefaultListableBeanFactory。
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// Register aliases for bean name, if any.
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String aliase : aliases) {
registry.registerAlias(beanName, aliase);
}
}
}
依赖注入,即在运行期由容器将依赖关系注入到组件之中
1、依赖注入发生的时间
当Spring IoC容器完成了Bean定义资源的定位、载入和解析注册以后,IoC容器中已经管理类Bean定义的相关数据,但是此时IoC容器还没有对所管理的Bean进行依赖注入,依赖注入在以下两种情况发生:
(1).用户第一次通过getBean方法向IoC容索要Bean时,IoC容器触发依赖注入。
(2).当用户在Bean定义资源中为
2、在BeanFactory中我们看到getBean(String…)函数,它的具体实现在AbstractBeanFactory中
依赖注入实现在以下两个方法中:
(1).createBeanInstance:生成Bean所包含的java对象实例。
(2).populateBean :对Bean属性的依赖注入进行处理。
分析:AbstractAutowireCapableBeanFactory类的populateBean方法
// 依赖注入的具体实现
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
// 获取Bean的依赖属性
PropertyValues pvs = mbd.getPropertyValues();
if (bw == null) {
if (!pvs.isEmpty()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
// 对属性进行处理
applyPropertyValues(beanName, mbd, bw, pvs);
}
// 对属性进行处理
applyPropertyValues(beanName, mbd, bw, pvs); -- > resolveValueIfNecessary(Object argName, Object value)
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
String refName = ref.getBeanName();
refName = String.valueOf(evaluate(refName));
if (ref.isToParent()) {
if (this.beanFactory.getParentBeanFactory() == null) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Can't resolve reference to bean '" + refName +
"' in parent factory: no parent factory available");
}
return this.beanFactory.getParentBeanFactory().getBean(refName);
}
else {
// 获取引用的bean,注入依赖关系前,需要对依赖进行实例化
Object bean = this.beanFactory.getBean(refName);
// 真正注入依赖的方法
this.beanFactory.registerDependentBean(refName, this.beanName);
return bean;
}
}
catch (BeansException ex) {
throw new BeanCreationException(
this.beanDefinition.getResourceDescription(), this.beanName,
"Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
}
}
方法中refName是当前Bean所依赖的Bean的名字,那么beanFactory获取到的就是当前Bean所依赖的Bean的实例。也就是说在对当前Bean进行依赖注入前要先获取依赖的Bean的实例,即对当前Bean进行依赖注入之前要先实例化依赖的Bean。
获取到依赖的实例之后,还要维护当前Bean和依赖的Bean之间的依赖关系,需要将他们之间的依赖关系保存起来。保存依赖关系的实现在registerDependentBean方法中。
//为指定的Bean注入依赖的Bean
public void registerDependentBean(String beanName, String dependentBeanName) {
//处理Bean名称,将别名转换为规范的Bean名称
String canonicalName = canonicalName(beanName);
//多线程同步,保证容器内数据的一致性
//先从容器中:bean名称-->当前bean被依赖的bean
synchronized (this.dependentBeanMap) {
//获取给定名称Bean的所有依赖Bean名称
Set dependentBeans = this.dependentBeanMap.get(canonicalName);
if (dependentBeans == null) {
//为Bean设置依赖Bean信息
dependentBeans = new LinkedHashSet(8);
this.dependentBeanMap.put(canonicalName, dependentBeans);
}
//向容器中:bean名称-->当前bean被依赖的bean
//即,将Bean所依赖的Bean添加到容器的集合中
dependentBeans.add(dependentBeanName);
}
//从容器中:bean名称-->当前bean所依赖的bean
//Bean的依赖Bean
synchronized (this.dependenciesForBeanMap) {
Set dependenciesForBean = this.dependenciesForBeanMap.get(dependentBeanName);
if (dependenciesForBean == null) {
dependenciesForBean = new LinkedHashSet(8);
this.dependenciesForBeanMap.put(dependentBeanName, dependenciesForBean);
}
//向容器中:bean名称-->当前bean所依赖的bean
//即,将Bean所依赖的Bean添加到容器的集合中
dependenciesForBean.add(canonicalName);
}
}
Spring IoC容器的autowiring属性自动依赖注入是一个很方便的特性,可以简化开发时的配置,但是凡是都有两面性,自动属性依赖注入也有不足,首先,Bean的依赖关系在配置文件中无法很清楚地看出来,对于维护造成一定困难。其次,由于自动依赖注入是Spring容器自动执行的,容器是不会智能判断的,如果配置不当,将会带来无法预料的后果,所以自动依赖注入特性在使用时还是综合考虑。
IOC容器的作用是管理对象之间的依赖关系,通过前面的分析,我们已知道Spring通过dependentBeanMap和dependenciesForBeanMap两个集合来管理依赖关系。
具体过程是:
a.遍历从BeanDefinition中获取到的属性集合,这些属性集合也就是当前Bean所依赖的集合,遍历 实例化这些属性(getBean())。
b.dependentBeanMap :然后再根据依赖属性的名称获取引用到该依赖属性实例的Bean的名称的集合,并将当前的beanName加入到集合中。
c.dependenciesForBeanMap :最后根据当前beanName获取当前Bean的依赖属性的名称的集合,并将依赖属性的名称加入到集合中。