看spring源码深度解析,记录一下第二章容器的基本实现。
启动spring
启动spring的main方法
public static void main(String[] args) {
//首先自己定义一个bean.xml文件,里面定义一个简单的bean标签就行。
Resource resource = new ClassPathResource("bean.xml");
//实例化一个beanfactory工厂,用来处理bean的一些实例化的东西,实际开发很少这样用。
BeanFactory factory = new DefaultListableBeanFactory();
//XmlBeanDefinitionReader是用来解析bean.xml文件的,把xml解析成elemet之后当成参数放到BeanFactory工厂进行解析,
BeanDefinitionReader bdr = new XmlBeanDefinitionReader((BeanDefinitionRegistry) factory);
//调用加载bean的方法了,这开始真真的把xml里面定义的属性编程一个一个的java对象了。
//看过程就说从这里开始看起。
bdr.loadBeanDefinitions(resource);
Student student = factory.getBean("stu", Student.class);
System.out.printf("。。。。。。" + student);
}
bdr.loadBeanDefinitions(resource);
这行代码开始加载,点进去就进到XmlBeanDefinitionReader
的loadBeanDefinitions
方法
loadBeanDefinitions方法就是这样的。
@Override
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//这个loadBeanDefinitions方法又调用重载方法loadBeanDefinitions,传入的参数是EncodedResource
return loadBeanDefinitions(new EncodedResource(resource));
}
loadBeanDefinitions(EncodedResource encodedResource) 这个方法的代码说这样的
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);
}
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
//转换成inpustStream,这个就是我们常用的输入流了,xml转换成流之后就能转换成element元素了。
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//这个方法也是做资源的转换,真真的操作就是下面这个方法。
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
。。。。省略那些catch异常的代码
}
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());的方法代码如下
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//这里把InputSource转换成了Document,看到这个就想起我们熟悉的xml了吧,哈哈。
Document doc = doLoadDocument(inputSource, resource);
//调用下面这个方法之后就完成了bean的注册了,bean的注册是spring的核心。
int count = registerBeanDefinitions(doc, resource);
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + count + " bean definitions from " + resource);
}
return count;
}
.........省略那些catch异常的代码。
}
int count = registerBeanDefinitions(doc, resource);的代码是这样的
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//实例化BeanDefinitionDocumentReader,这个就是定义bean的对象,解析bean的各种标签,这里默认的实现是DefaultBeanDefinitionDocumentReader这个类,这里是调用createBeanDefinitionDocumentReader()方法通过反射完成实例化的。
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//获取当前定义的bean的个数,第一次进来这里肯定说0.
int countBefore = getRegistry().getBeanDefinitionCount();
//这里就开始进入解析bean标签的方法了。
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
//两个数字相减得到当前定义了多少个bean了。
return getRegistry().getBeanDefinitionCount() - countBefore;
}
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));方法点进去,一步一步点下去就掉用到doRegisterBeanDefinitions(Element root)这个方法
protected void doRegisterBeanDefinitions(Element root) {
//下面这两个应该是spring的父子容器,暂时还没看明白是啥意思。
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
//判断是不是使用的spring的默认标签
if (this.delegate.isDefaultNamespace(root)) {
//解析profile标签,profile标签就是我们平时用来定义spring的多给环境的。
//这里逻辑判断比较简单,就是进行验证一下。
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(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);
//解析bean标签了
parseBeanDefinitions(root, this.delegate);
//这个方法是空的,方便继续此类的人进行二次开发。
postProcessXml(root);
this.delegate = parent;
}
parseBeanDefinitions(root, this.delegate);方法的代码如下
/**
* Parse the elements at the root level in the document:
* "import", "alias", "bean".
* @param root the DOM root element of the document
*/
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)) {
//解析以及注册BeanDefinitions对象
parseDefaultElement(ele, delegate);
}
else {
//解析自定义标签,spring支持自定义标签,用来实现自己的业务,比如说dubbo的标签,apollo的标签哈。
delegate.parseCustomElement(ele);
}
}
}
}
else {
//解析自定义标签,spring支持自定义标签,用来实现自己的业务,比如说dubbo的标签,apollo的标签哈。
delegate.parseCustomElement(root);
}
}
spring的自定义标签的定义和解析网上有很多的例子。
到这里为止spring读取xml文件转换成Element就完成了,接下来就是把Element转换spring的bean对象。书中的例子也是到这里就当成了一章了。