默认标签:

上一篇说到spring的默认标签和自定义标签,发现这里面东西还蛮多的。决定还是拆开来写。今天就来好好聊聊这两块是怎么玩的,首先我们先看看默认标签:

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//import标签解析
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//alias标签解析 别名标签
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//bean标签
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}

可以看到一共就4个标签:import,alias,bean,beans。 其中最重要的,复杂的,最常用的就是bean标签了,由于篇幅受限(不是因为懒),就只分析bean标签的解析了,其实大抵是相同的,比如import标签其实就是解析完放到一个叫import的map缓存中,alias放到alias的map标签。接下来就详细介绍下bean标签的解析。

点进去看看:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析document,封装成BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) { //装饰者设计模式,加上SPI设计思想
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try { //完成document到BeanDefinition对象转换后,对BeanDefinition对象进行缓存注册
// 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));
}
}

首先看如何封装成beanDefinition对象的:

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE); List<String> 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.isTraceEnabled()) {
logger.trace("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
} //检查beanName是否重复
if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
} //通过标签配置解析城beanDefinition对象
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.isTraceEnabled()) {
logger.trace("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;
}

主要看这一行:AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);

点进去:

public AbstractBeanDefinition parseBeanDefinitionElement(
Element ele, String beanName, @Nullable BeanDefinition containingBean) { this.parseState.push(new BeanEntry(beanName)); String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
} try {
//1.创建GenericBeanDefinition对象
AbstractBeanDefinition bd = createBeanDefinition(className, parent); //2.解析bean标签的属性,并把解析出来的属性设置到BeanDefinition对象中
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT)); //3.解析bean中的meta标签
parseMetaElements(ele, bd); //4.解析bean中的lookup-method标签
parseLookupOverrideSubElements(ele, bd.getMethodOverrides()); //5.解析bean中的replaced-method标签
parseReplacedMethodSubElements(ele, bd.getMethodOverrides()); //6.解析bean中的constructor-arg标签
parseConstructorArgElements(ele, bd); //7.解析bean中的property标签
parsePropertyElements(ele, bd); //8.解析bean中的qualifier标签
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;
}

我在上面备注都标了序号,下面为了方便就直接以序号代替,首先看1:

点到里面:

public static AbstractBeanDefinition createBeanDefinition(
@Nullable String parentName, @Nullable String className, @Nullable 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;
}

其实就是new了一个GenericBeanDefinition对象,设值。

再看2:其实就是把autowried,primary,factoryMethodName等bean标签属性设置到beanDefinition对象中,

3-8做的基本都一致,只不过解析bean标签不同的属性,这时候beanDefinition对象已经有了,是不是有人觉得已经结束了,

回到bean标签解析刚开始的地方:

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//解析document,封装成BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) { //装饰者设计模式,加上SPI设计思想
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try { //完成document到BeanDefinition对象转换后,对BeanDefinition对象进行缓存注册
// 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));
}
}

是否发现封装beanDefinition对象(其实这时候已经是BeanDefinitionHolder)只是第一步,接下来我们再看看这个所谓的装饰者设计模式和spi思想是个啥玩意(没意义的代码一直往下点就完事了):

public BeanDefinitionHolder decorateBeanDefinitionIfRequired(
Element ele, BeanDefinitionHolder definitionHolder, @Nullable BeanDefinition containingBd) { BeanDefinitionHolder finalDefinition = definitionHolder; //根据bean标签属性装饰BeanDefinitionHolder,比如<bean class="xx" p:username="jack"/>
//
// Decorate based on custom attributes first.
NamedNodeMap attributes = ele.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node node = attributes.item(i);
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
} //根据bean标签子元素装饰BeanDefinitionHolder
// Decorate based on custom nested elements.
NodeList children = ele.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node node = children.item(i);
if (node.getNodeType() == Node.ELEMENT_NODE) {
finalDefinition = decorateIfRequired(node, finalDefinition, containingBd);
}
}
return finalDefinition;
}

这块解析主要分为bean标签元素和子元素,可以看到其实调用的方法是一样的:decorateIfRequired(Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd):

public BeanDefinitionHolder decorateIfRequired(
Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) { //根据node获取到node的命名空间,形如:http://www.springframework.org/schema/p
String namespaceUri = getNamespaceURI(node);
if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) { //这里有SPI服务发现的思想,根据配置文件获取namespaceUri对应的处理类
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if (handler != null) { //调用NamespaceHandler处理类的decorate方法,开始具体装饰过程,并返回装饰完的对象
BeanDefinitionHolder decorated =
handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
if (decorated != null) {
return decorated;
}
}
else if (namespaceUri.startsWith("http://www.springframework.org/")) {
error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
}
else {
// A custom namespace, not to be handled by Spring - maybe "xml:...".
if (logger.isDebugEnabled()) {
logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
}
}
}
return originalDef;
}

首先看一下spring对spi的实现:

public NamespaceHandler resolve(String namespaceUri) {
//获取spring中所有jar包里面的 "META-INF/spring.handlers"文件,并且建立映射关系
Map<String, Object> handlerMappings = getHandlerMappings(); //根据namespaceUri:http://www.springframework.org/schema/p,获取到这个命名空间的处理类
Object handlerOrClassName = handlerMappings.get(namespaceUri);
if (handlerOrClassName == null) {
return null;
}
else if (handlerOrClassName instanceof NamespaceHandler) {
return (NamespaceHandler) handlerOrClassName;
}
else {
String className = (String) handlerOrClassName;
try {
Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
"] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
}
NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass); //调用处理类的init方法,在init方法中完成标签元素解析类的注册
namespaceHandler.init();
handlerMappings.put(namespaceUri, namespaceHandler);
return namespaceHandler;
}
catch (ClassNotFoundException ex) {
throw new FatalBeanException("Could not find NamespaceHandler class [" + className +
"] for namespace [" + namespaceUri + "]", ex);
}
catch (LinkageError err) {
throw new FatalBeanException("Unresolvable class definition for NamespaceHandler class [" +
className + "] for namespace [" + namespaceUri + "]", err);
}
}
}

1.获取所有META-INF/spring.handlers路径下的映射关系,那么这文件里面到底是啥呢:

http\://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
http\://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
http\://www.springframework.org/schema/util=org.springframework.beans.factory.xml.UtilNamespaceHandler

不知道大家有没有注意过spring的xml文件上面写的:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"

xmlns:jack="http://www.xiangxueedu.com/schema/mytags"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.xiangxueedu.com/schema/mytags
http://www.xiangxueedu.com/schema/mytags.xsd"
default-lazy-init="false">

有没有发现这就是spring.handlers文件里面的,首先就是用这个作为key来找到后面对应的类路径,找到之后放入缓存(一开始看的时候,没注意缓存名称handlerMappings和新容器名称一致,以为可以作为spring的commiter了,仔细一看,是我想太多了),拿到所有对应spring.handlers文件里面的信息,通过key去取到类路径,然后反射实例化,得到NamespaceHandler处理类实例,调用处理类的init方法,这个方法很重要,比如ContextNamespaceHandler:

public void init() {
registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
}

有木有发现,我们最最最常用的标签component-scan的解析器就是在这里注册的

拿到handler之后,我们需要去开始decorate装饰流程了:

public BeanDefinitionHolder decorate(
Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
//拿到节点的处理器类
BeanDefinitionDecorator decorator = findDecoratorForNode(node, parserContext);
//实际处理
return (decorator != null ? decorator.decorate(node, definition, parserContext) : null);
}

看一下获取处理器类的流程:

private BeanDefinitionDecorator findDecoratorForNode(Node node, ParserContext parserContext) {
BeanDefinitionDecorator decorator = null;
String localName = parserContext.getDelegate().getLocalName(node);
if (node instanceof Element) {
decorator = this.decorators.get(localName);
}
else if (node instanceof Attr) {
decorator = this.attributeDecorators.get(localName);
}
else {
parserContext.getReaderContext().fatal(
"Cannot decorate based on Nodes of type [" + node.getClass().getName() + "]", node);
}
if (decorator == null) {
parserContext.getReaderContext().fatal("Cannot locate BeanDefinitionDecorator for " +
(node instanceof Element ? "element" : "attribute") + " [" + localName + "]", node);
}
return decorator;
}

看代码逻辑就是从decorators,attributeDecorators这俩缓存中拿的,然后你再回去看一下刚才init方法,其实就是在这一步放入缓存的,比如AopNamespaceHandler:

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());
}
点开registerBeanDefinitionDecorator方法
protected final void registerBeanDefinitionDecorator(String elementName, BeanDefinitionDecorator dec) {
this.decorators.put(elementName, dec);
}

剩下的感兴趣的同学可以自己去摸索摸索。

拿到处理类之后,我们就要去做具体的装饰操作,其实就是根据不同的装饰器,基于原有功能添加一些aop拦截之类的附加功能,至此BeanDefinition对象算是完成了。

下一步就是将beanDefinition注册到缓存当中,毕竟后面要用嘛,我们看一下注册的详细逻辑:

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty");
Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) {
try {
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
"Validation of bean definition failed", ex);
}
} //先判断BeanDefinition是否已经注册
BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
if (existingDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
}
else if (existingDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (logger.isInfoEnabled()) {
logger.info("Overriding user-defined bean definition for bean '" + beanName +
"' with a framework-generated bean definition: replacing [" +
existingDefinition + "] with [" + beanDefinition + "]");
}
}
else if (!beanDefinition.equals(existingDefinition)) {
if (logger.isDebugEnabled()) {
logger.debug("Overriding bean definition for bean '" + beanName +
"' with a different definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
else {
if (logger.isTraceEnabled()) {
logger.trace("Overriding bean definition for bean '" + beanName +
"' with an equivalent definition: replacing [" + existingDefinition +
"] with [" + beanDefinition + "]");
}
}
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
//把beanDefinition缓存到map中
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition); //把beanName放到beanDefinitionNames list中,这个list着重记住,bean实例化的时候需要用到
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
} if (existingDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}

抛开这些校验不看,其实也就是判断缓存是否存在,存在覆盖掉beanDefinitionMap,否则在添加到beanDefinitionMap,同时还要添加一份到beanDefinitionNames中。至此,结束bean标签的解析。

自定义标签:

上面我们说完了默认标签的解析,用到了核心思想就是用到了spi机制将需要的解析器使用xml配置,解耦合,通过解析器将标签解析成beanDefinition对象形式。下面我们主要分析自定义标签:

首先点进去看看:

public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
String namespaceUri = getNamespaceURI(ele);
if (namespaceUri == null) {
return null;
}
//还是spi获取handler
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));
}

可以看到,其实这边的handler获取还是用的spi机制去获取的,而且,只有第一次获取才会去读配置文件,以后都是读取缓存handlerMapping,拿到handler之后,就开始具体的标签解析的逻辑了:

public BeanDefinition parse(Element element, ParserContext parserContext) {
//首先找到对应的beanDefinition处理器
BeanDefinitionParser parser = findParserForElement(element, parserContext);
return (parser != null ? parser.parse(element, parserContext) : null);
}

不知道还记不记得上面说的spi找到处理器类之后初始化的过程,初始化的过程其实就是将处理器类放到一个叫parsers的缓存里面,了解这些之后我们再来看下beanDefinition处理器是怎么获取的:

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;
}

是不是发现,这个其实就是在前面初始化的时候塞的那个缓存,拿到处理器之后,我们就可以安安心心去解析标签了,点开org.springframework.jms.config.AbstractListenerContainerParser#parse:

public final BeanDefinition parse(Element element, ParserContext parserContext) {
//1.创建beanDefinition对象
AbstractBeanDefinition definition = parseInternal(element, parserContext);
if (definition != null && !parserContext.isNested()) {
try {
String id = resolveId(element, definition, parserContext);
if (!StringUtils.hasText(id)) {
parserContext.getReaderContext().error(
"Id is required for element '" + parserContext.getDelegate().getLocalName(element)
+ "' when used as a top-level tag", element);
}
String[] aliases = null;
if (shouldParseNameAsAliases()) {
String name = element.getAttribute(NAME_ATTRIBUTE);
if (StringUtils.hasLength(name)) {
aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
}
}
//2.beanDefinition对象封装成BeanDefinitionHolder对象
BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
//3.注册到缓存
registerBeanDefinition(holder, parserContext.getRegistry());
if (shouldFireEvents()) {
BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
postProcessComponentDefinition(componentDefinition);
parserContext.registerComponent(componentDefinition);
}
}
catch (BeanDefinitionStoreException ex) {
String msg = ex.getMessage();
parserContext.getReaderContext().error((msg != null ? msg : ex.toString()), element);
return null;
}
}
return definition;
}

和之前解析默认标签是一样的,1.创建beanDefinition对象  2.封装成BeanDefinitionHolder对象  3.将封装好的对象注册到缓存(塞到beanDefinitionMap和beanDefinitionNames里面)

总结:   

        看到这里,其实细心的人应该发现了,到处都是缓存,这些缓存提升了效率,但是我们看起来会很绕,可怜我一个一个去找啊。其实现在想想,没有必要对于每个细节都去了解,时间长了还是会忘,我们看源码,最需要了解的还是思想,思想理解了,后面自己写的时候才能慢慢做到融会贯通。写完了标签的解析,感受还是蛮深的,其实自己也想过,如果让我来设计的话,我会怎么做,我可能会将所有的bean直接反射实例化,放到缓存当中,以前甚至觉得,spring这么做是否有点画蛇添足的感觉,我觉得很多人都会这么想吧(绝对不是因为我菜),spring源码读多了,发现里面细节真的很多,对于不同生命周期的管理,让我们可以再bean创建到销毁的任意一个阶段都可以操作。而他对bean的创建,我们也可以做撒手掌柜,确实是做到了改变了java的生态,牛逼plus。

            

从零开始学spring源码之xml解析(二):默认标签和自定义标签解析的更多相关文章

  1. 从零开始学spring源码之xml解析(一):入门

    谈到spring,首先想到的肯定是ioc,DI依赖注入,aop,但是其实很多人只是知道这些是spring核心概念,甚至不知道这些代表了什么意思,,作为一个java程序员,怎么能说自己对号称改变了jav ...

  2. 从零开始学spring源码之ioc预热:bean的拓展和beanProcessor注册

    上篇聊完了bean的解析,说起来做的事情很简单,把xml文件里面配置的标签全部解析到spring容器里面,但是spring做的时候,花了那么大代价去做,后面看看到底值不值得呢. 接下来看看prepar ...

  3. Spring源码学习-容器BeanFactory(四) BeanDefinition的创建-自定义标签的解析.md

    写在前面 上文Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签对Spring默认标签的解析做了详解,在xml元素的解析中,Spri ...

  4. Spring源码阅读笔记04:默认xml标签解析

    上文我们主要学习了Spring是如何获取xml配置文件并且将其转换成Document,我们知道xml文件是由各种标签组成,Spring需要将其解析成对应的配置信息.之前提到过Spring中的标签包括默 ...

  5. Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作

    写在前面 上文 Spring源码学习-容器BeanFactory(一) BeanDefinition的创建-解析资源文件主要讲Spring容器创建时通过XmlBeanDefinitionReader读 ...

  6. Spring源码学习(2)——默认标签的解析

    上一篇随笔说到Spring对于默认标签和自定义标签的解析方法是不同的,这里详细看一下Spring对于默认标签的解析. private void parseDefaultElement(Element ...

  7. Spring源码分析(十二)FactoryBean的使用

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 一般情况下,Spring通过反射机制利用bean的class属性指定实现 ...

  8. Spring如何解析XML文件——Spring源码之XML初解析

    首先,在我的这篇博客中已经说到容器是怎么初步实现的,并且要使用XmlBeanDefinitionReader对象对Xml文件进行解析,那么Xml文件是如何进行解析的,将在这片博客中进行一些陈述. 数据 ...

  9. Spring源码学习-容器BeanFactory(三) BeanDefinition的创建-解析Spring的默认标签

    写在前面 上文Spring源码学习-容器BeanFactory(二) BeanDefinition的创建-解析前BeanDefinition的前置操作中Spring对XML解析后创建了对应的Docum ...

随机推荐

  1. 探究 position-sticky 失效问题

    CSS 的 position 值中,有一个非常有用的值 -- position: sticky,通常会被用于各种吸顶,吸底,吸边的效果中. 如果你对 sticky 还不太熟悉,可以先看看我的这篇文章: ...

  2. Android虚拟机Genymotion的安装与使用

    1.首先官网下载genymotion-2.12.2-vbox包,首选第一个带有box,点击安装 2.安装完毕选择自己要用的安卓系统,建议选择安卓4.0以上全部 3.启动打开虚拟机 4.安装外部APP, ...

  3. Android插件换肤 一.实现原理

    学习缺的不是时间,而是耐心 目的 1.搞懂系统获取资源文件到在加载布局的整个流程是自己实现换肤功能的理论基础 2.提高分析源码.追踪源码的能力 要点 1.XmlResourceParser (通过这个 ...

  4. intellij idea svn不能更新和提交

    进入设置–version control – subversion如下图,将前边的选项的勾全部去掉,点击ok

  5. springboot日志输出到文件

    今天来谈一谈日志,主要是说一说springboot的日志,因为最近在学习springboot.首先在写代码的时候,要养成记日志的习惯,这点真的很重要,因为之前吃了很多亏.过去我对日志很不在意,该有的日 ...

  6. Java动态代理分析

    Java动态代理机制的出现,使得Java开发人员不用手工编写代理类,只要简单地制定一组接口及委托类对象,便能动态地获得代理类.代理类会负责将所有的方法调用分配到委托对象上反射执行,配置执行过程中,开发 ...

  7. gcc/g++命令参数

    在windows环境下,我们运行一程序,只需要在VS中点击运行按键即可,VS帮我们做完了程序的预处理.编译.汇编.链接阶段 但是在linux环境下,我们只能借助gcc/g++完成这一系列的操作 -o参 ...

  8. 七、Elasticsearch+elasticsearch-head的安装+Kibana环境搭建+ik分词器安装

    一.安装JDK1.8 二.安装ES 三个节点:master.slave01.slave02 1.这里下载的是elasticsearch-6.3.1.rpm版本包 https://www.elastic ...

  9. Linux 下挂载新硬盘方法(转)

    1.关闭服务器加上新硬盘   2.启动服务器,以root用户登录   3.查看硬盘信息 #fdisk -l Disk /dev/sda: 42.9 GB, 42949672960 bytes 255  ...

  10. Github美化 添加徽章

    Github美化 添加徽章 0. 前言 1. 准备 2. 开始 a. 打开shields.io b.制作静态徽章 c.制作动态徽章 d. 结果 3.额外 0. 前言 之前看见很多大项目都有很多勋章,比 ...