3.1.2AbstrctBeanDefiniton属性 ~ 3.1.5通知监听器解析及注册完成
3.1.2AbstrctBeanDefiniton属性
至此我们完成了XML文档中的bean标签到GenericBeanDefinition对象的转换,也就是说到这里,XML中所有配置都可以在GenericBeanDefinition实例中找到对于的位置。
GenericBeanDefinition只是子类实现,大部分属性都保存在了AbstractBeanDefinition的属性中。
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor implements BeanDefinition, Cloneable { /** * Constant for the default scope name: {@code ""}, equivalent to singleton * status unless overridden from a parent bean definition (if applicable). */ public static final String SCOPE_DEFAULT = ""; /** * Constant that indicates no external autowiring at all. * @see #setAutowireMode */ public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO; /** * Constant that indicates autowiring bean properties by name. * @see #setAutowireMode */ public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME; /** * Constant that indicates autowiring bean properties by type. * @see #setAutowireMode */ public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE; /** * Constant that indicates autowiring a constructor. * @see #setAutowireMode */ public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR; /** * Constant that indicates determining an appropriate autowire strategy * through introspection of the bean class. * @see #setAutowireMode * @deprecated as of Spring 3.0: If you are using mixed autowiring strategies, * use annotation-based autowiring for clearer demarcation of autowiring needs. */ @Deprecated public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT; /** * Constant that indicates no dependency check at all. * @see #setDependencyCheck */ public static final int DEPENDENCY_CHECK_NONE = 0; /** * Constant that indicates dependency checking for object references. * @see #setDependencyCheck */ public static final int DEPENDENCY_CHECK_OBJECTS = 1; /** * Constant that indicates dependency checking for "simple" properties. * @see #setDependencyCheck * @see org.springframework.beans.BeanUtils#isSimpleProperty */ public static final int DEPENDENCY_CHECK_SIMPLE = 2; /** * Constant that indicates dependency checking for all properties * (object references as well as "simple" properties). * @see #setDependencyCheck */ public static final int DEPENDENCY_CHECK_ALL = 3; /** * Constant that indicates the container should attempt to infer the * {@link #setDestroyMethodName destroy method name} for a bean as opposed to * explicit specification of a method name. The value {@value} is specifically * designed to include characters otherwise illegal in a method name, ensuring * no possibility of collisions with legitimately named methods having the same * name. * <p>Currently, the method names detected during destroy method inference * are "close" and "shutdown", if present on the specific bean class. */ public static final String INFER_METHOD = "(inferred)"; @Nullable private volatile Object beanClass; /** * bean的作用范围,对应bean属性scope * 默认=空字符串=单例singleton,通过isSingleton()方法判断 */ @Nullable private String scope = SCOPE_DEFAULT; /** * 是否是抽象,对应bean属性abstract */ private boolean abstractFlag = false; /** * 是否延迟加载,对应bean属性lazy-init */ @Nullable private Boolean lazyInit; /** * 自动注入模式,对应bean属性autowire。默认不 */ private int autowireMode = AUTOWIRE_NO; /** * 依赖检查,Spring3.0后弃用这个属性 */ private int dependencyCheck = DEPENDENCY_CHECK_NONE; /** * 用来表示一个bean的实例化依靠另一个bean先实例化,对应bean属性depend-on */ @Nullable private String[] dependsOn; /** * autowire-candidate属性设置为false,这样容器在查找自动装配时,将不考虑该bean。 * 即它不会被考虑作为其他bean自动装配的候选者,但是该bean本身还是可以使用自动装配来注入其他bean */ private boolean autowireCandidate = true; /** * 自动装配是当出现多个候选者时,将作为首选者,对应bean属性primary */ private boolean primary = false; /** * 用来记录Qualifier,对应子元素qualifier */ private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(); @Nullable private Supplier<?> instanceSupplier; /** * 允许访问非公开的构造器和方法,程序设置 */ private boolean nonPublicAccessAllowed = true; /** * 是否以一种宽松的模式解析构造函数,默认是true * 如果是false,则在如下情况 * interface ITest() * class ITestImpl implement ITest{}; * class Main{ * Main(ITest i){} * Main(ITestImpl i){} * } * 抛出异常,因为Spring无法准确定位哪个构造函数 * 程序异常 */ private boolean lenientConstructorResolution = true; /** * 用于调用工厂类 */ @Nullable private String factoryBeanName; /** * 用于实例化工厂类方法 */ @Nullable private String factoryMethodName; /** * 记录构造函数注入属性,对应bean属性constructor-arg */ @Nullable private ConstructorArgumentValues constructorArgumentValues; /** * 普通属性集合 */ @Nullable private MutablePropertyValues propertyValues; /** * 方法重写的操作者,记录lookup-method、replace-method元素 */ private MethodOverrides methodOverrides = new MethodOverrides(); /** * 初始化方法,对应bean属性init-method */ @Nullable private String initMethodName; /** * 销毁方法,对应bean属性destroy-method */ @Nullable private String destroyMethodName; /** * 是否执行init-method,程序设置 */ private boolean enforceInitMethod = true; /** * 是否执行destroy-method,程序设置 */ private boolean enforceDestroyMethod = true; /** * 是否用户定义的而不是应用程序本身定义的,创建AOP的时候为true,程序设置 */ private boolean synthetic = false; /** * 定义这个bean的应用,APPLICATION:用户,INFRASTRUCTURE:完全内部使用,与用户无关 * SUPPORT某些复杂配置的一部分,程序设置 */ private int role = BeanDefinition.ROLE_APPLICATION; /** * bean的描述 */ @Nullable private String description; /** * 这个bean定义的资源 */ @Nullable private Resource resource; }
3.1.3解析默认标签中的自定义标签
这里的自定义标签其实是属性,与上面说的不同,上面说的是Bean。
到这里我们完成了默认标签的解析与提取过程,或许涉及的内容太多,我们已经忘了从哪个函数开始,我们再次回顾下默认标签解析函数的起始函数
DefaultBeanDefinitionDocumentReader /** * Process the given bean element, parsing the bean definition * and registering it with the registry. * * 1)首先委托BeanDefinitionDelegate类的parseBeanDefinitionElement方法进行元素解析, * 返回BeanDefinitionHolder类型的实例bdholder, * 经过这个方法后,bdholder已经包含了配置文件中的配置的各种属性(class、name、id、alias......) * 2)当返回的bdholder不为空的情况下若存在默认标签的子节点下有自定义属性,还需要对自定义标签解析。 * 3)解析完成后,需要对解析后的bdholder进行注册。委托给BeanDefinitionReaderUtils的regiestBeanDefinition方法 * 4)最后发出响应事件,通知相关监听器,这个bean已经加载完毕。 * */ protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) { //委托BeanDefinitionDelegate类的parseBeanDefinitionElement方法进行元素解析, //返回BeanDefinitionHolder类型的实例bdholder, //经过这个方法后,bdholder已经包含了配置文件中的配置的各种属性(class、name、id、alias......) BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); if (bdHolder != null) { //当返回的bdholder不为空的情况下若存在默认标签的子节点下有自定义属性,还需要对自定义标签解析。 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); try { // Register the final decorated instance. //注册bean 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)); } }
接下里我们解析bdHolder = delegate.decorateBeanDefinitionIfRequired(ele,bdHolder);
解析适用于下面的配置(bean使用的是默认的标签配置,但是其中的子元素却使用了自定义配置):
<bean id="test" class="MyTest">
<mybean:user username="aaa" />
</bean>
让我们尽量解析
BeanDefinitionParserDelegate public BeanDefinitionHolder decorateBeanDefinitionIfRequired( Element ele, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) { BeanDefinitionHolder finalDefinition = originalDef; // 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); } // 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; } public BeanDefinitionHolder decorateIfRequired( Node node, BeanDefinitionHolder originalDef, @Nullable BeanDefinition containingBd) { //获取自定义标签的命名空间 String namespaceUri = getNamespaceURI(node); //对于非默认标签进行修饰 if (namespaceUri != null && !isDefaultNamespace(namespaceUri)) { //根据命名空间查找对应的处理器 NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri); if (handler != null) { //进行修饰 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/schema/")) { 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; }
大致逻辑:
首先获取属性或者命名空间,以此来判断该元素或者属性是否是自定义标签,然后找出自定义类型所在的NamespaceHandler并进行进一步解析。在自定义标签解析那块(Bean)再说,现在暂时略过。
3.1.4注册解析BeanDefinition
解析了,装饰的也装饰了,BeanDefinition已经满足后续使用的要求了。是时候该注册了。 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
BeanDefinitionReaderUtils /** * Register the given bean definition with the given bean factory. * @param definitionHolder the bean definition including name and aliases * @param registry the bean factory to register with * @throws BeanDefinitionStoreException if registration failed * * 对于配置文件,解析也解析完成了,装饰也装饰完了 * 对于得到的BeanDefinition已经满足后续的使用要求了,唯一还剩下的就是注册了 * */ public static void registerBeanDefinition( BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException { // Register bean definition under primary name. //使用beanName作为唯一标识 String beanName = definitionHolder.getBeanName(); registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition()); // Register aliases for bean name, if any. //注册所有别名 String[] aliases = definitionHolder.getAliases(); if (aliases != null) { for (String alias : aliases) { registry.registerAlias(beanName, alias); } } }
BeanDefinition会被注册到BeanDefinitionRegistry的实例中。注册分为两部分,通过beanName注册、通过别名注册。
1.通过beanName注册
嗯。没错,注册就是Spring将BeanDefinition放入map中,beanName作为key,只不过除此之外,它还做了点别的事情。
DefaultListableBeanFactory 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 { /** * 注册前最后一次校验,这里的校验不同于之前的XML文件校验 * 主要是对于AbstractBeanDefinition属性中的MethodOverrides校验, * 校验MethodOverrides是否与工厂方法并存或者MethodOverrides对应的方法存不存在 */ ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } //beanDefinitionMap是全局变量,这里定会存在并发访问的情况。 //使用CurreHashMap是不是可以解决这个情况? BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); //处理已经注册的beanName的情况 if (existingDefinition != null) { //如果对应的BeanName已经注册在配置中配置了bean不允许被覆盖,则抛出异常 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 { //alreadyCreated这个set集合不为空 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; removeManualSingletonName(beanName); } } else { //alreadyCreated这个set集合为空 // Still in startup registration phase //注册beanDefinition this.beanDefinitionMap.put(beanName, beanDefinition); //记录beanName this.beanDefinitionNames.add(beanName); removeManualSingletonName(beanName); } this.frozenBeanDefinitionNames = null; } if (existingDefinition != null || containsSingleton(beanName)) { //重制所有对beanName对应的缓存 resetBeanDefinition(beanName); } else if (isConfigurationFrozen()) { clearByTypeCache(); } }
大致逻辑:
1.对AbstractBeanDefinition的校验,在解析XML文件时我们提过校验,但是此校验非彼校验,之前的校验时针对于XML格式的校验,而此时是针对AbstractBeandefinition的MethodOverrides属性的。
2.对beanName已经注册的情况的处理。如果设置了不允许bean的覆盖,则需要抛出异常,否则直接覆盖。
3.放入map(Map<String, BeanDefinition> beanDefinitionMap)缓存
4.清除解析之前留下的对应beanName的缓存。
2.通过别名注册BeanDefinition
SimpleAliasRegiestry public void registerAlias(String name, String alias) { Assert.hasText(name, "'name' must not be empty"); Assert.hasText(alias, "'alias' must not be empty"); synchronized (this.aliasMap) { //如果beanName与alias相同的话不记录alias,并删除对应的alias if (alias.equals(name)) { this.aliasMap.remove(alias); if (logger.isDebugEnabled()) { logger.debug("Alias definition '" + alias + "' ignored since it points to same name"); } } else { String registeredName = this.aliasMap.get(alias); if (registeredName != null) { if (registeredName.equals(name)) { // An existing alias - no need to re-register return; } //如果alias不允许被覆盖则抛出异常 if (!allowAliasOverriding()) { throw new IllegalStateException("Cannot define alias '" + alias + "' for name '" + name + "': It is already registered for name '" + registeredName + "'."); } if (logger.isDebugEnabled()) { logger.debug("Overriding alias '" + alias + "' definition for registered name '" + registeredName + "' with new target name '" + name + "'"); } } //当A->B存在时,若再次出现A->C->B时候则会抛出异常 //当beanName A 指定 别名 B时候 checkForAliasCircle(name, alias); this.aliasMap.put(alias, name); if (logger.isTraceEnabled()) { logger.trace("Alias definition '" + alias + "' registered for name '" + name + "'"); } } } }
大致逻辑:
1.若alias与beanName名称相同则不需要处理并删除alias
2.若alias已经被使用并被指定列一个beanName则需要用户设置覆盖属性。
3.alias循环检查。
4.注册alias。
3.1.5通知监听器解析及注册完成
通过代码 getReaderContext().fireComponentRegistered(new BeanComponent-Definition(bdHolder))完成此工作。这里的实现只为扩展,当程序人员需要对BeanDefinition事件进行监听的时候,可以通过注册监听器的方式并将处理逻辑写入监听器中,目前Spring中并没有对此事件做任何逻辑处理。

浙公网安备 33010602011771号