美文网首页
3-AbstractBeanDefinition

3-AbstractBeanDefinition

作者: 鹏程1995 | 来源:发表于2020-02-14 17:53 被阅读0次

背景简介

出现的原因

之前我们分析了 BeanDefinition 的职责及在接口中做的基本操作。为了满足不同的具体用途,我们会定义不同的BeanDefinition的具体实现。

但是这些实现除了一些具体的属性和操作是定制的,大部分都是模版性质的代码或者说都是共同的功能,所以抽出一个基本的实现类来实现通用操作就变得有必要了。

这种模式我们在之前看集合类的那一系列操作经常看到,这些设计参考的设计模式是适配器模式/模版方法模式

区分这两种模式的一个比较明显的点是:

  • 你在Abstract***中将主干逻辑实现了,专门设置/留下一些核心方法让子类定制,这个一般是模版方法模式
  • 如果你在Abstract***中只是将通用的一些逻辑从头搞定,或者只是做了默认实现,这个一般是适配器模式

职责

AbstractBeanDefinitionBeanDefinition中规定的方法中最通用的一些操作进行了实现,方便子类将注意力专门放到自己关注的领域。

注意点

源码

类继承结构分析

思路引导

我们在读 Spring 源码时经常会遇到一个类要实现的接口是 n 多个接口继承出来的。继承树超级复杂,我们如果要对这样的接口进行一个 Abstract****的实现,涉及的东西超级多。

但是我们这样想一下:

接口进行了 n 多个的继承,接口继承的目的很明显:功能加强/融合。一般很少有接口仅仅是用来定义的,接口一般都对应自己定义的功能的默认实现。

我们直接继承那个默认实现,是不是就可以不用专门在我们的Abstract****中全都写一遍了?

这种思路有个致命的缺点:

Java 的单继承带来了很多的便利,例如从根源上避免了 C++ 的多继承引起的问题,也不会了解虚基类的那些。

但是还是会带来一些问题的,例如如果你要实现的那个接口如果它的继承数量 n >= 2 ,可能找不到合适的功能默认实现类来继承。

如果遇到这个问题,我门可以考虑慢慢继承。。。。。二合一、二合一的来。。。。有点像最开始的XmlBeanFactory的继承树那样。

实践

我们来分析一下——BeanDefinition继承了两个接口:

  1. AttributeAccessor
  2. BeanMetadataElement

这明显 >=2 了,我们试一下二合一、二合一的来。。。。

整合AttributeAccessor

先找其中一个的实现类,我们找 AttributeAccessor吧。这个接口是一个属性的增删改查的功能。我们找到了它的一个实现类AttributeAccessorSupport,用LinkedHashMap为内部数据结构做了一个基本实现。

整合BeanMetadataElement

这个接口定义了一个获得 bean 的源数据内容的函数。我们直接继承AttributeAccessorSupport ,然后实现BeanMetadataElement。这样就把这两个功能整到一起了。有了BeanMetadataAttributeAccessor这个类,就是内部定义了一个source的属性用来存源数据内容,剩下的AttributeAccessor的功能都依靠父类的实现。

整合进来

上面我们用BeanMetadataAttributeAccessor完成了两个功能的整合。接下来直接继承它就行了。然后把所有的注意力都放到BeanDefinition中定义的方法中来。

结果对比

1.png

唯一比较突兀的是考虑到一些复制操作,AbstractBeanDefinition实现了Clonable接口。虽然继承树看着贼鸡儿乱,但是根据上面的分析,基本就透彻了。此处不再赘述,我们直接看AbstractBeanDefinition中对BeanDefinition中定义的方法的描述。

其实这也是一个类注重一个功能,是设计模式中的单一职责原则

内部源码解析

AbstractBeanDefinition主要做了三件事:

  1. 扩展了一下 BD 中定义的常量。
  2. 针对 BD中定义的那一串 getter/setter方法,定义了一把子实例属性。
  3. 多定义了一些属性,并定义了一些工具方法。

常量扩展

// 对 Bean
/**
 * 默认生命周期,如果有父容器,就跟随父容器的生命周期;如果没有父容器,就是单例声明周期。
 */
public static final String SCOPE_DEFAULT = "";

/**
 * 不自动注入属性
 *
 */
public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;

/**
 * 通过属性命名自动注入属性
 */
public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;

/**
 * 通过属性类型自动注入类型
 */
public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;

/**
 * 此 Bean 的实例在构建时采用构造函数注入。
 * 【当然,这里只是说使用构造函数,并通过构造函数带进去一些东西。构造出实例后还是可以通过 上面的配置来进行
 *  根据 命名/类型 继续进行属性注入】
 */
public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;

/**
 * 构建此 Bean 的实例时不进行任何依赖检测
 */
public static final int DEPENDENCY_CHECK_NONE = 0;

/**
 * 构建此 Bean 的实例时只检测对象依赖【复杂依赖】
 */
public static final int DEPENDENCY_CHECK_OBJECTS = 1;

/**
 * 构建此 Bean 的实例时只检测常用类型依赖【简单依赖】
 */
public static final int DEPENDENCY_CHECK_SIMPLE = 2;

/**
 * 构建此 Bean 的实例时检测所有依赖
 */
public static final int DEPENDENCY_CHECK_ALL = 3;

/**
 * 一个常量,在记录 Bean 的销毁要调用的方法时如果设置成这个值就表明这不是个具体的方法名。方法名称需要
 * 自行推断。
 *
 * 【这个常量的值设置成这样是为了保证不会有某些很变态的方法命名和这个常量的值冲突了】
 */
public static final String INFER_METHOD = "(inferred)";

实例变量定义

看名字基本就能和 BeanDefinition中的getter/setter对应上了。不再赘述。

@Nullable
private volatile Object beanClass;
@Nullable
private String scope = SCOPE_DEFAULT;
private boolean abstractFlag = false;
private boolean lazyInit = false;
@Nullable
private String[] dependsOn;
private boolean autowireCandidate = true;
private boolean primary = false;
@Nullable
private String factoryBeanName;
@Nullable
private String factoryMethodName;
@Nullable
private ConstructorArgumentValues constructorArgumentValues;
@Nullable
private MutablePropertyValues propertyValues;
@Nullable
private String initMethodName;
private int role = BeanDefinition.ROLE_APPLICATION;
@Nullable
private String description;
@Nullable
private Resource resource;

扩展的变量及方法

扩展的变量

/**
 * 存储此 BD 的 Qualifier 值。这个有点像是别名的,可以在声明 Bean 时写上 n 个,在要用时,通过
 * 使用 Qualifier 进行限制。
 **/
private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();

/**
 * 指明对此 Bean 中的依赖属性如何寻找到对应的值
 **/
private int autowireMode = AUTOWIRE_NO;

/**
 * 配置是否对此 Bean 中配置的依赖进行检测
 **/ 
private int dependencyCheck = DEPENDENCY_CHECK_NONE;

/**
 * 用来记录生成此 Bean 实例的一个工厂方法引用【算是最直白最爽的一种实例化方法了】
 **/
@Nullable
private Supplier<?> instanceSupplier;

/**
 * 设置是否允许通过特殊手段接触 Bean 的 Class 中的非公有方法【个人感觉主要是在配置实例化 Bean 时找构造
 * 函数时的一些策略用吧】
 **/
private boolean nonPublicAccessAllowed = true;

/**
 * 在配置实例化 Bean 时找构造函数时是否采用宽松策略策略用吧
 **/
private boolean lenientConstructorResolution = true;

/**
 * 用来保存在 BeanDefinition 配置中的一些方法覆盖的设置
 **/
@Nullable
private MethodOverrides methodOverrides;

/**
 * 配置当要销毁实例 Bean 时要调用的方法
 **/
@Nullable
private String destroyMethodName;

/**
 * 指明配置的初始化方法是不是默认的那个【????】【可能是为了简化逻辑提供的一个标记量?】
 **/
private boolean enforceInitMethod = true;

/**
 * 指明配置的销毁方法是不是默认的那个【????】【可能是为了简化逻辑提供的一个标记量?】
 **/
private boolean enforceDestroyMethod = true;

/**
 * 指明此 BD 是否是合成的
 *【合成的 = 用户自己定义的 = 不是应用程序定义的 = 不用执行一些后处理器钩子???】【最后一点不确定】
 **/
private boolean synthetic = false;

可见,这些新增的属性主要是以下几个方面:

  1. 对 Bean 的一些功能的增加/增强
  2. 一些捷径标记的设定

扩展的方法

大概有两种,一种是提供更细粒度的控制,直接粘贴代码,不再赘述。

/**
 * Return a description of the resource that this bean definition
 * came from (for the purpose of showing context in case of errors).
 */
@Override
@Nullable
public String getResourceDescription() {
    return (this.resource != null ? this.resource.getDescription() : null);
}

/**
 * Set a description of the resource that this bean definition
 * came from (for the purpose of showing context in case of errors).
 */
public void setResourceDescription(@Nullable String resourceDescription) {
    this.resource = (resourceDescription != null ? new DescriptiveResource(resourceDescription) : null);
}

/**
 * Return the originating BeanDefinition, or {@code null} if none.
 * Allows for retrieving the decorated bean definition, if any.
 * <p>Note that this method returns the immediate originator. Iterate through the
 * originator chain to find the original BeanDefinition as defined by the user.
 */
@Override
@Nullable
public BeanDefinition getOriginatingBeanDefinition() {
    return (this.resource instanceof BeanDefinitionResource ?
            ((BeanDefinitionResource) this.resource).getBeanDefinition() : null);
}

/**
 * Set the originating (e.g. decorated) BeanDefinition, if any.
 */
public void setOriginatingBeanDefinition(BeanDefinition originatingBd) {
    this.resource = new BeanDefinitionResource(originatingBd);
}

第二种是为 Bean 的初始化提供了一些辅助接口。

/**
 * 校验此 BD 的定义有没有明显的问题
 *
 * @throws BeanDefinitionValidationException in case of validation failure
 */
public void validate() throws BeanDefinitionValidationException {
  // 如果使用工厂方法,那就不能做方法增强
    if (hasMethodOverrides() && getFactoryMethodName() != null) {
        throw new BeanDefinitionValidationException(
                "Cannot combine static factory method with method overrides: " +
                        "the static factory method must create the instance");
    }

    if (hasBeanClass()) {
        prepareMethodOverrides();
    }
}

/**
 * 对要增强的方法过一遍。
 * 
 * 如果有明显的配置不合理,例如方法不存在,直接报错结束。
 * 如果有捷径可走,比如方法没有重载,标记一下方便后续处理
 *
 * @throws BeanDefinitionValidationException in case of validation failure
 */
public void prepareMethodOverrides() throws BeanDefinitionValidationException {
    // Check that lookup methods exists.
    if (hasMethodOverrides()) {
        Set<MethodOverride> overrides = getMethodOverrides().getOverrides();
        synchronized (overrides) {
            for (MethodOverride mo : overrides) {
                prepareMethodOverride(mo);
            }
        }
    }
}

/**
 * 具体实现方法,调用 core 包的 util 找到对应的数量即可。那个 util 应该是用反射处理了一下。
 *
 * @param mo the MethodOverride object to validate
 * @throws BeanDefinitionValidationException in case of validation failure
 */
protected void prepareMethodOverride(MethodOverride mo) throws BeanDefinitionValidationException {
    int count = ClassUtils.getMethodCountForName(getBeanClass(), mo.getMethodName());
    if (count == 0) {
        throw new BeanDefinitionValidationException(
                "Invalid method override: no method with name '" + mo.getMethodName() +
                        "' on class [" + getBeanClassName() + "]");
    } else if (count == 1) {
        // 只有一个,说明我们要覆盖的方法不需要重写
        // Mark override as not overloaded, to avoid the overhead of arg type checking.
        mo.setOverloaded(false);
    }
}

相关文章

  • 3-AbstractBeanDefinition

    背景简介 出现的原因 之前我们分析了 BeanDefinition 的职责及在接口中做的基本操作。为了满足不同的具...

网友评论

      本文标题:3-AbstractBeanDefinition

      本文链接:https://www.haomeiwen.com/subject/tkjjfhtx.html