看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對象。書中的例子也是到這裏就當成了一章了。