这一篇主要是讲用载入bean的过程。其实就是IOC.低调 低调。。
我把重要的都挑出来了。一步步往下看就明白spring载入bean.xml里面bean的原理 。
感觉像候杰的 MFC深入浅出,哈哈。
观看规则
接下 表示下一层代码。
接上 表示最近上面要调用的代码的详细部分。
public class XmlBeanFactory extends DefaultListableBeanFactory {
//新建一个bean分析器,把this注册到里面是因为,在分析器解析好一个bean时,可以立即用这个this里的注册方法去保存bean,往下看就明白。任何bean到最后都是保存在XmlBeanFactory里的(其实是DefaultListableBeanFactory)。
private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
//载入xml文件
this.reader.loadBeanDefinitions(resource); //往下->
}
}
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
//接上
public int loadBeanDefinitions(Resource resource) throws BeansException {
InputStream is = null;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(this.validating);
DocumentBuilder docBuilder = factory.newDocumentBuilder();
docBuilder.setErrorHandler(this.errorHandler);
if (this.entityResolver != null) {
docBuilder.setEntityResolver(this.entityResolver);
}
is = resource.getInputStream();
//用Xerces解析xml,生成dom
Document doc = docBuilder.parse(is);
//registerBeanDefinitions分析dom
return registerBeanDefinitions(doc, resource); //往下
}
//接上
public int registerBeanDefinitions(Document doc, Resource resource) throws BeansException {
XmlBeanDefinitionParser parser = (XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);
//这个parserClass 是 DefaultXmlBeanDefinitionParser.class
return parser.registerBeanDefinitions(this, doc, resource); //往下->
}
}
public class DefaultXmlBeanDefinitionParser implements XmlBeanDefinitionParser {
//明显就是bean.xml里面出现的很熟悉的标签,说明已经快到底层类了
public static final String AUTOWIRE_BY_NAME_VALUE = "byName";
public static final String AUTOWIRE_BY_TYPE_VALUE = "byType";
public static final String DEFAULT_LAZY_INIT_ATTRIBUTE = "default-lazy-init";
public static final String DEFAULT_DEPENDENCY_CHECK_ATTRIBUTE = "default-dependency-check";
public static final String DEFAULT_AUTOWIRE_ATTRIBUTE = "default-autowire";
public static final String NAME_ATTRIBUTE = "name";
public static final String ALIAS_ATTRIBUTE = "alias";
public static final String BEAN_ELEMENT = "bean";
public static final String ID_ATTRIBUTE = "id";
public static final String PARENT_ATTRIBUTE = "parent";
public static final String CLASS_ATTRIBUTE = "class";
public static final String SINGLETON_ATTRIBUTE = "singleton";
public static final String LAZY_INIT_ATTRIBUTE = "lazy-init";
public static final String AUTOWIRE_ATTRIBUTE = "autowire";
//...
//接上
public int registerBeanDefinitions(BeanDefinitionReader reader, Document doc, Resource resource) throws BeanDefinitionStoreException {
this.beanDefinitionReader = reader;
this.resource = resource;;
Element root = doc.getDocumentElement();
//...
//这里准备开始正式解析bean
int beanDefinitionCount = parseBeanDefinitions(root);//往下->
//这个beanDefinitionCount 就是解析出了多少个<bean></bean>
//...
return beanDefinitionCount;
}
protected int parseBeanDefinitions(Element root) throws BeanDefinitionStoreException {
//Xerces开始循环找<bean>标签
NodeList nl = root.getChildNodes();
int beanDefinitionCounter = 0;
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element) node;
if // ...
//..
else if (BEAN_ELEMENT.equals(node.getNodeName())) {//这里是重点,开始解析bean
beanDefinitionCounter++;
//分两步走,看下面详解。1.先把bean放到BeanDefinitionHolder
BeanDefinitionHolder bdHolder = parseBeanDefinitionElement(ele);//往下 1.->
//2.然后XmlBeanFactory去注册
BeanDefinitionReaderUtils.registerBeanDefinition(
bdHolder, this.beanDefinitionReader.getBeanFactory()); //往下 2. ->
}
}
}
return beanDefinitionCounter;
}
//接上1. 哈哈,下面是第一步,是正常解析bean,在同一个类中
protected BeanDefinitionHolder parseBeanDefinitionElement(Element ele) throws BeanDefinitionStoreException {
//...
//下面可以看到其实最底层的解析bean在同一个类的parseBeanDefinitionElement方法里。因为spring把bean封装成BeanDefinition 再把BeanDefinition 封装成BeanDefinitionHolder
BeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName);//往下
//...
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
//接上 , 这个方法很长,毕竟<bean>里attribute很多。
protected BeanDefinition parseBeanDefinitionElement(Element ele, String beanName) throws BeanDefinitionStoreException {
try {
//下面解析<bean>里的<property>,这个我不分析了。
MutablePropertyValues pvs = parsePropertyElements(ele, beanName);
//将BeanDefinition封装成AbstractBeanDefinition
AbstractBeanDefinition bd = BeanDefinitionReaderUtils.createBeanDefinition(
className, parent, cargs, pvs, this.beanDefinitionReader.getBeanClassLoader());
//...
return bd;
}
catch (/*...*/)
//...
}
}
}
//bean解析部分到此结束。。。。
//接上2. 这里是第二部,注册部分,回到上面注释里的分两部走这里。
public class BeanDefinitionReaderUtils {
public static void registerBeanDefinition(
BeanDefinitionHolder bdHolder, BeanDefinitionRegistry beanFactory) throws BeansException {
//beanFactory就是XmlBeanFactory,其实是它的父类 DefaultListableBeanFactory在执行registerBeanDefinition
beanFactory.registerBeanDefinition(bdHolder.getBeanName(), bdHolder.getBeanDefinition()); //往下
//...
}
}
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {
/** Whether to allow re-registration of a different definition with the same name */
private boolean allowBeanDefinitionOverriding = true;
/** Map of bean definition objects, keyed by bean name */
//下面是真正藏bean的地方,其实是个Map,跟我预想的一样。
private final Map beanDefinitionMap = new HashMap();
//下面List可能是给bean的名字做个索引,这是我的初步猜想。
/** List of bean definition names, in registration order */
private final List beanDefinitionNames = new ArrayList();
//接上
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
//...
Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
//根据allowBeanDefinitionOverriding这个变量来决定在bean.xml里的bean万一有同名的情况下否覆盖,因为allowBeanDefinitionOverriding默认是true,所以覆盖。
if (!this.allowBeanDefinitionOverriding) {
throw new BeanDefinitionStoreException(...);
}
else {
//...只用注释提醒相同bean将要被覆盖了
}
}
else {
//索引List里加上这个bean名字
this.beanDefinitionNames.add(beanName);
}
//将bean藏在map里。用名字来索引。
this.beanDefinitionMap.put(beanName, beanDefinition);
}
//...
}
//结束
可以看到其实spring就是把bean.xml解析到一个map里。
至于获取bean的方法 ,我不用说大家都知道了,到了底层就是 map.get("bean name");
万流归终啊。。。。
over
分享到:
相关推荐
springBean加载过程源码解析文档,附有代码类名和行数
Spring bean 一般通过配置文件和注解进行加载,如果要实现jar或class文件,动态实现spring bean 的动态加载,并通过UrlClassLoader完成jar和class文件的加载。可以实现jar的热替换。spring的bean动态加载则需要对...
Spring加载Bean: AbstractBeanFactory.xmind
Spring 大量引入了Java 的Reflection机制,通过动态调用的方式避免硬编码方式的约束,并在此基础上建立了其核心组件...org.springframework.beans包中包括了这些核心组件的实现类,这里就提供了该包中的源码。
本篇将对定义在 XMl 文件中的 bean,从静态的的定义到变成可以使用的对象的过程,即 bean 的加载和获取的过程进行一个整体的了解
spring 重新动态加载数据库或xml中的bean,可以不用重启tomcat
Spring Bean 加载顺序 实验小例子
Spring Bean创建初始化流程
spring源码bean生命周期doScan扫描过程图
该项目展示spring配置文件的那些bean的加载顺序
spring 获取bean spring 获取bean spring 获取bean spring 获取bean spring 获取bean spring 获取bean spring 获取bean spring 获取bean
spring bean配置 运行环境:eclipse 构建工具:maven 不提供maven构建,maven用来解决jar包的依赖
spring-bean 源码依赖的jar包,用于spring源码部署的时候使用
spring基于xml配置加载bean 的demo 了解spring的反射机制
spring运行过程中动态注册bean,代码实例
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架,如何在程序中获取Spring配置的bean呢?下面通过本文给大家介绍Java中Spring获取bean方法小结,对spring获取bean方法相关知识感兴趣的朋友一起学习...
Spring 的bean的作用域总结,详细的总结了 Spring 的bean的作用域
个人觉得spring3.2的源代码比较好编译,没啥脾气,像我之前下载的spring的最新版本源代码,还有spring4.0的源代码,不论是使用jdk1.6还是1.7甚至是1.8编译都出问题,结果还是觉得spring3.2编译过程轻松一点,配合...
spring加载restful(文档+程序源码).zip spring加载restful(文档+程序源码).zip
07 源码分析-spring的bean工厂准备工作