1. 程式人生 > >Spring原始碼閱讀之Bean載入(xml)1

Spring原始碼閱讀之Bean載入(xml)1

先上兩張圖,簡單的畫了一下beanFactory各個類之間的關係,XmlBeanFactorybean載入的入口和核心。Spring中大量使用了設計模式和UML中的設計原則,比如單一職責原則,從類圖可以看出,BeanFactory派生的各個介面,根據名字的不同,都增加了響應的單一職責的功能,職責功能即為類名。XmlBeanFactory繼承自DefaultListableBeanFactory,使用了XmlBeanDefinitionReaderDefaultListableBeanFactorybean工廠的基本實現類,封裝了大部分Bean工廠的功能內容,XmlBeanDefinitionReader

是載入註冊Bean到工廠的核心實現類。

直接從原始碼流程說起:

XmlBeanFactory 使用成員變數XmlBeanDefinitionReader載入Bean定義資料。

如下:

private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

呼叫

public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader.loadBeanDefinitions(resource);
}

進入XmlBeanDefinitionReader

// Load bean definitions from the specified XML file
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
 
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
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 (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}
// Actually load bean definitions from the specified XML file.
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
}
catch (SAXException ex) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(),
"XML document from " + resource + " is invalid", ex);
}
catch (ParserConfigurationException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Parser configuration exception parsing XML from " + resource, ex);
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"IOException parsing XML document from " + resource, ex);
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(resource.getDescription(),
"Unexpected exception parsing XML document from " + resource, ex);
}
}

Spring中真正起作用的方法一般會用do開頭。doLoadDocument方法獲取Document物件後,進入註冊方法。

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}

進入DefaultBeanDefinitionDocumentReaderregisterBeanDefinitions方法,註冊bean等到工廠類。

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}

protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> 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(getReaderContext(), root, parent);
 
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
return;
}
}
}
 
preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
 
this.delegate = parent;
}

這裡使用了BeanDefinitionParserDelegate,故名思意,這是一個分派器,用於決定使用哪個BeanDefinitionParser來解析,if (this.delegate.isDefaultNamespace(root)) {判斷跳過Spring自身的類,preProcessXml(root)以及postProcessXml(root);

留空,不做處理,用於子類繼承,下面看下這兩個方法的註釋:

/**
 * Allow the XML to be extensible by processing any custom element types first,
 * before we start to process the bean definitions. This method is a natural
 * extension point for any other custom pre-processing of the XML.
 * <p>The default implementation is empty. Subclasses can override this method to
 * convert custom elements into standard Spring bean definitions, for example.
 * Implementors have access to the parser's bean definition reader and the
 * underlying XML resource, through the corresponding accessors.
 * @see #getReaderContext()
 */
protected void preProcessXml(Element root) {
}
/**
 * Allow the XML to be extensible by processing any custom element types last,
 * after we finished processing the bean definitions. This method is a natural
 * extension point for any other custom post-processing of the XML.
 * <p>The default implementation is empty. Subclasses can override this method to
 * convert custom elements into standard Spring bean definitions, for example.
 * Implementors have access to the parser's bean definition reader and the
 * underlying XML resource, through the corresponding accessors.
 * @see #getReaderContext()
 */
protected void postProcessXml(Element root) {
}

大概意思是,通過使用者自定義型別,使得XML可以被擴充套件

/**
 * 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)) {
parseDefaultElement(ele, delegate);
}
else {
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}

DefaultBeanDefinitionDocumentReader

ParseCustomElement方法解析自定義標籤,parseDefaultElement解析預設標籤

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}

//自定義

public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler == null) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
return null;
}
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}

這裡解析了XML的資訊,跟蹤進去,使用了NamespaceHandler的實現類的parse方法,它會根據節點的型別,找到一種合適的解析BeanDefinitionParser(接口),他們預先被spring註冊好了,放在一個HashMap中,看下NamespaceHandler的簡單實現類AopNamespaceHandlerNamespaceHandlerSupport

AopNamespaceHandler

public class AopNamespaceHandler extends NamespaceHandlerSupport {
/**
 * Register the {@link BeanDefinitionParser BeanDefinitionParsers} for the
 * '{@code config}', '{@code spring-configured}', '{@code aspectj-autoproxy}'
 * and '{@code scoped-proxy}' tags.
 */
@Override
public void init() {
// In 2.0 XSD as well as in 2.1 XSD.
registerBeanDefinitionParser("config", new ConfigBeanDefinitionParser());
registerBeanDefinitionParser("aspectj-autoproxy", new AspectJAutoProxyBeanDefinitionParser());
registerBeanDefinitionDecorator("scoped-proxy", new ScopedProxyBeanDefinitionDecorator());
 
// Only in 2.0 XSD: moved to context namespace as of 2.1
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
}
}

AopNamespaceHandlerinit()方法可以看出,這裡註冊了一系列BeanDefinitionParsers,比如aspectj-autoproxy代理。其實就是在Map<String, BeanDefinitionParser> parsers 增加相應解析類,然後根據節點型別獲取不同的解析類。

NamespaceHandlerSupport

public abstract class NamespaceHandlerSupport implements NamespaceHandler {
private final Map<String, BeanDefinitionParser> parsers =
new HashMap<String, BeanDefinitionParser>();
 
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
return findParserForElement(element, parserContext).parse(element, parserContext);
}
/**
 * Locates the {@link BeanDefinitionParser} from the register implementations using
 * the local name of the supplied {@link Element}.
 */
private BeanDefinitionParser findParserForElement(Element element, ParserContext parserContext) {
String localName = parserContext.getDelegate().getLocalName(element);
BeanDefinitionParser parser = this.parsers.get(localName);
if (parser == null) {
parserContext.getReaderContext().fatal(
"Cannot locate BeanDefinitionParser for element [" + localName + "]", element);
}
return parser;
}
}

繼續上面預設標籤的解析:

對於以下四種類型:

IMPORT_ELEMENT

ALIAS_ELEMENT

BEAN_ELEMENT

NESTED_BEANS_ELEMENT

個人理解,首次解析root根節點,對應與xml檔案中的第一個beans標籤如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
default-lazy-init="true">
</beans>

root包含的應該是這一級別的內容,而這裡面又可以配置<bean/>標籤和<beans profile/>標籤等,profile常用於配置不同資料來源,實現開發環境和生產環境,這裡面的<beans/>對應於NESTED_BEANS_ELEMENT級別。然後對root內不同級別生成不同bean定義。先看下root下解析import或者bean。解析bean標籤:

/**
 * Process the given bean element, parsing the bean definition
 * and registering it with the registry.
 */
DefaultBeanDefinitionDocumentReader中:
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
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));
}
}


processBeanDefinition處理Element並生成BeanDefinitionHolder,然後註冊例項,

getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

觸發註冊事件。

進一步跟蹤方法,進入BeanDefinitionParserDelegate委託類:

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
 
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
return parseBeanDefinitionElement(ele, null);
}
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
 
List<String> aliases = new ArrayList<String>();
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;
}

首先獲取元素的idname屬性,進行一些處理後,使用parseBeanDefinitionElement解析元素並生成BeanDefinition

繼續在委託類BeanDefinitionParserDelegate中:

public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, BeanDefinition containingBean) {
 
this.parseState.push(new BeanEntry(beanName));
 
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
 
try {
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
 
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
 
parseMetaElements(ele, bd);
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
 
parseConstructorArgElements(ele, bd);
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
 
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
 
return bd;
}
catch (ClassNotFoundException ex) {
error("Bean class [" + className + "] not found", ele, ex);
}
catch (NoClassDefFoundError err) {
error("Class that bean class [" + className + "] depends on not found", ele, err);
}
catch (Throwable ex) {
error("Unexpected failure during bean definition parsing", ele, ex);
}
finally {
this.parseState.pop();
}
 
return null;
}

首先獲取元素的classparent屬性,根據這兩個屬性呼叫createBeanDefinition建立AbstractBeanDefinition

protected AbstractBeanDefinition createBeanDefinition(String className, String parentName)
throws ClassNotFoundException {
 
return BeanDefinitionReaderUtils.createBeanDefinition(
parentName, className, this.readerContext.getBeanClassLoader());
}
 
public static AbstractBeanDefinition createBeanDefinition(
String parentName, String className, ClassLoader classLoader) throws ClassNotFoundException {
 
GenericBeanDefinition bd = new GenericBeanDefinition();
bd.setParentName(parentName);
if (className != null) {
if (classLoader != null) {
bd.setBeanClass(ClassUtils.forName(className, classLoader));
}
else {
bd.setBeanClassName(className);
}
}
return bd;
}

createBeanDefinition方法中,建立GenericBeanDefinition物件,載入class物件並賦到值到GenericBeanDefinition,設定className。回到parseBeanDefinitionElement方法,生成抽象bean定義類後,繼續呼叫

//解析bean標籤下的Attributes
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//解析元資料
parseMetaElements(ele, bd);
//解析lock-up,沒有設定工廠生成bean方法可忽略
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//解析replace-method
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
 
parseConstructorArgElements(ele, bd);
parsePropertyElements(ele, bd);
parseQualifierElements(ele, bd);
 
bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));

等方法完成一系列後繼任務。

解析標籤下是否有相應各種屬性:

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName,
BeanDefinition containingBean, AbstractBeanDefinition bd) {
 
if (ele.hasAttribute(SINGLETON_ATTRIBUTE)) {
error("Old 1.x 'singleton' attribute in use - upgrade to 'scope' declaration", ele);
}
else if (ele.hasAttribute(SCOPE_ATTRIBUTE)) {
bd.setScope(ele.getAttribute(SCOPE_ATTRIBUTE));
}
else if (containingBean != null) {
// Take default from containing bean in case of an inner bean definition.
bd.setScope(containingBean.getScope());
}
 
if (ele.hasAttribute(ABSTRACT_ATTRIBUTE)) {
bd.setAbstract(TRUE_VALUE.equals(ele.getAttribute(ABSTRACT_ATTRIBUTE)));
}
 
String lazyInit = ele.getAttribute(LAZY_INIT_ATTRIBUTE);
if (DEFAULT_VALUE.equals(lazyInit)) {
lazyInit = this.defaults.getLazyInit();
}
bd.setLazyInit(TRUE_VALUE.equals(lazyInit));
 
String autowire = ele.getAttribute(AUTOWIRE_ATTRIBUTE);
bd.setAutowireMode(getAutowireMode(autowire));
 
String dependencyCheck = ele.getAttribute(DEPENDENCY_CHECK_ATTRIBUTE);
bd.setDependencyCheck(getDependencyCheck(dependencyCheck));
 
if (ele.hasAttribute(DEPENDS_ON_ATTRIBUTE)) {
String dependsOn = ele.getAttribute(DEPENDS_ON_ATTRIBUTE);
bd.setDependsOn(StringUtils.tokenizeToStringArray(dependsOn, MULTI_VALUE_ATTRIBUTE_DELIMITERS));
}
 
String autowireCandidate = ele.getAttribute(AUTOWIRE_CANDIDATE_ATTRIBUTE);
if ("".equals(autowireCandidate) || DEFAULT_VALUE.equals(autowireCandidate)) {
String candidatePattern = this.defaults.getAutowireCandidates();
if (candidatePattern != null) {
String[] patterns = StringUtils.commaDelimitedListToStringArray(candidatePattern);
bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
}
}
else {
bd.setAutowireCandidate(TRUE_VALUE.equals(autowireCandidate));
}
 
if (ele.hasAttribute(PRIMARY_ATTRIBUTE)) {
bd.setPrimary(TRUE_VALUE.equals(ele.getAttribute(PRIMARY_ATTRIBUTE)));
}
 
if (ele.hasAttribute(INIT_METHOD_ATTRIBUTE)) {
String initMethodName = ele.getAttribute(INIT_METHOD_ATTRIBUTE);
if (!"".equals(initMethodName)) {
bd.setInitMethodName(initMethodName);
}
}
else {
if (this.defaults.getInitMethod() != null) {
bd.setInitMethodName(this.defaults.getInitMethod());
bd.setEnforceInitMethod(false);
}
}
 
if (ele.hasAttribute(DESTROY_METHOD_ATTRIBUTE)) {
String destroyMethodName = ele.getAttribute(DESTROY_METHOD_ATTRIBUTE);
bd.setDestroyMethodName(destroyMethodName);
}
else {
if (this.defaults.getDestroyMethod() != null) {
bd.setDestroyMethodName(this.defaults.getDestroyMethod());
bd.setEnforceDestroyMethod(false);
}
}
 
if (ele.hasAttribute(FACTORY_METHOD_ATTRIBUTE)) {
bd.setFactoryMethodName(ele.getAttribute(FACTORY_METHOD_ATTRIBUTE));
}
if (ele.hasAttribute(FACTORY_BEAN_ATTRIBUTE)) {
bd.setFactoryBeanName(ele.getAttribute(FACTORY_BEAN_ATTRIBUTE));
}
 
return bd;
}

主要是對根據不同屬性,對BeanDefinition進行設定。

執行了以上方法後,xml中標籤資訊被封裝在BeanDefinitionHolder中,

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
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));
}
}

註冊到工廠容器

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

Bean標籤解析完畢。同理,如果是<beans/>標籤,解析<beans/>以及其下自標籤,流程大概相同。

相關推薦

Spring原始碼閱讀Bean載入xml1

先上兩張圖,簡單的畫了一下beanFactory各個類之間的關係,XmlBeanFactory是bean載入的入口和核心。Spring中大量使用了設計模式和UML中的設計原則,比如單一職責原則,從類圖可以看出,BeanFactory派生的各個介面,根據名字的不同,都增加了

spring原始碼解析IOC容器------載入和註冊

  上一篇跟蹤了IOC容器對配置檔案的定位,現在我們繼續跟蹤程式碼,看看IOC容器是怎麼載入和註冊配置檔案中的資訊的。開始之前,首先我們先來了解一下IOC容器所使用的資料結構-------BeanDefinition,它是一個上層介面,有很多實現類,分別對應不同的資料載體。我們平時開發的時候,也會定義很多po

mybatis原始碼解析Configuration載入

概要 上一篇,我們主要搭建了一個簡單的環境,這邊我們主要來分析下mybatis是如何來載入它的配置檔案Configuration.xml的。 分析 1 public class App { 2 public static void main(String[] args) { 3

mybatis原始碼解析Configuration載入

概述 上一篇我們講了configuation.xml中幾個標籤的解析,例如<properties>,<typeAlises>,<settings>等,今天我們來介紹剩下的兩個比較重要的標籤之一,<environments>,這個標籤主要用於我們訪問資料庫的配置

spring原始碼解析IOC容器

  學習優秀框架的原始碼,是提升個人技術水平必不可少的一個環節。如果只是停留在知道怎麼用,但是不懂其中的來龍去脈,在技術的道路上註定走不長遠。最近,學習了一段時間的spring原始碼,現在整理出來,以便日後溫故知新。   IOC容器是spring最核心的模組之一,是整個spring體系的基石,spring其

spring原始碼解析IOC容器——依賴注入

  上一篇主要是跟蹤了IOC容器對bean標籤進行解析之後存入Map中的過程,這些bean只是以BeanDefinition為載體單純的儲存起來了,並沒有轉換成一個個的物件,今天繼續進行跟蹤,看一看IOC容器是怎樣例項化物件的。   我們都使用過以下程式碼: 1 FileSystemXmlApplicati

Spring原始碼解析基礎應用

方法注入 在spring容器中,大部分bean的作用域(scope)是單例(singleton)的,少部分bean的作用域是原型(prototype),如果一個bean的作用域是原型,我們A bean的作用域是原型,B bean中以@Autowired的方式注入A,那麼B在A中依舊是單例。我們可以讓B類實現A

Spring原始碼解析基礎應用

組合Java配置 在XML中,我們可以使用<import/>標籤,在一個XML檔案中引入另一個XML檔案,在Java類中,我們同樣可以在一個配置類中用@Import引入另一個配置類,被引入的配置類中的@Bean也會載入到spring容器。程式碼如下: @Configuration public

Spring源碼閱讀Springs-beans容器的基本實現

beans 閱讀 gin com -i add wid ans lock 一、Spring-beans Spring源碼閱讀之Springs-beans(一)容器的基本實現

Spring第一天:Spring的概述、SpringIOC入門XMLSpringBean管理、Spring屬性注入

以前也學習過Spring框架,不過好久沒用,當時學完也沒做什麼總結,都忘的差不多了,今天再從頭開始學習一遍。無論是SSH還是SSM都離不開Spring,所以Spring還是很重要的,對於一個想要從事JavaEE開發的人,一定要好好學習Spring框架。Spring的學習計劃如下: 第一

Spring原始碼解讀——bean的生命週期(隨筆)

bean建立---初始化----銷燬的過程 容器管理bean的生命週期; 我們可以自定義初始化和銷燬方法;容器在bean進行到當前生命週期的時候來呼叫我們自定義的初始化和銷燬方法 構造(物件建立)     單例項:在容器啟動的時候建立物件     多例項:在每次獲取的時

Spring初探bean工廠

Spring是什麼?Spring的中文名是春天,它是軟體開發人的春天,是一個輕量級的控制反轉(IOC)和麵向切面(AOP)的容器框架。我以一個簡單的示例解構spring是怎樣管理java物件的。 首先,定義一個簡單的pojo,程式碼如下:package com.jvk.ke

Spring原始碼解析bean的建立

閱讀須知 Spring原始碼版本:4.3.8 文章中使用/* */註釋的方法會做深入分析 正文 之前我們都是在圍繞 ApplicationContext applicationContext = new ClassPathXmlApplicati

Spring 原始碼閱讀 深入理解 finishBeanFactoryInitialization

原始碼入口 上篇博文中我們看到了將Spring環境中的 BeanPostProcessor找出來,新增到BeanFactory中的beanPostProcessors中,統一維護,本片博文繼續往下拓展,看下Spring如何例項化bean,以及如何實現在bean的例項化通過各種各樣的後置處理器完成bean的增強

Spring原始碼分析Bean的建立過程詳解

前文傳送門: 1. [Spring原始碼分析之預啟動流程](https://mp.weixin.qq.com/s/bfbPJOlYo2Vz2UTSMWRGkw) 2. [Spring原始碼分析之BeanFactory體系結構](https://mp.weixin.qq.com/s/FDx0hmCp7dEfw

Spark原始碼分析Spark Shell

https://www.cnblogs.com/xing901022/p/6412619.html 文中分析的spark版本為apache的spark-2.1.0-bin-hadoop2.7。 bin目錄結構: -rwxr-xr-x. 1 bigdata bigdata 1089 Dec

PyTorch原始碼解讀torchvision.transforms

原文地址:https://blog.csdn.net/u014380165/article/details/79167753 PyTorch框架中有一個非常重要且好用的包:torchvision,該包主要由3個子包組成,分別是:torchvision.dat

SGISTL原始碼閱讀十七 stack

SGISTL原始碼閱讀十七 stack(棧) 前言 前面我們已經學習了序列式容器vector,list和deque。 本次要進行分析的是stack,它是一種先進後出(First In Lat Out,FILO)資料結構,在學習資料結構的時候應該都接觸過,在這裡stack是一個配接器(

雲客Drupal8原始碼分析外掛系統

以下內容僅是一個預覽,完整內容請見文尾: 至此本系列對外掛的介紹全部完成,涵蓋了系統外掛的所有知識 全文目錄(全文10476字): 例項化外掛 外掛對映Plugin mapping 外掛上下文  

Spring Boot 入門基礎篇

一、前言 Spring Boot 是由 Pivotal 團隊提供的全新框架,其設計目的是用來簡化新 Spring 應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。 本系列以快速入門為主,可當作工具小手冊閱讀