3. BeanDefinition の親インターフェース

前回の本では BeanDefinition の基本について説明しましたが、この記事では BeanDefinition ファミリ システムについて詳しく説明します。説明する前に、著者はもう一度 BeanDefinition ファミリーの継承関係図を提示しました。

画像.png

    
    /***
    BeanDefinition接口的父接口:
    
     1. AttributeAccessor
             1.1 实现类 AttributeAccessorSupport 作用是操作bd的属性,属性存放在LinkedHashMap。
             
     2. BeanMetadataElement
             2.1 实现类 BeanMetadataAttributeAccessor获取源即bd对应的class的磁盘文件位置
             2.2 实现类 BeanMetadataAttributeAccessor继承了AttributeAccessorSupport既可以操作属性值,也可以操作源
             2.3 属性封装对象 BeanMetadataAttribute
            
     ***/     
     
  public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement    

1. BeanDefinition の親インターフェース

前回のブログ投稿では BeanDefinition インターフェースの機能について詳しく説明しましたが、著者はこのインターフェースを中心に拡張する予定です。

まず BeanDefinition の親インターフェースを見てください。

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement

BeanDefinition インターフェースは、AttributeAccessor と BeanMetadataElement の 2 つのインターフェースを継承します。

つまりBeanDefinitionの実装クラスは同時に実現します

BeanDefinition、AttributeAccessor、BeanMetadataElement の 3 つのインターフェイスの関数。

1.1 AttributeAccessor: ロール操作 bd 属性

    /**
     *定义用于附加和访问BeanDefinition元数据的通用的接口,来自任意对象
     */
    public interface AttributeAccessor {
        /**
        将属性名为name的属性的属性值设置为value
        注意是BeanDefinition的属性
        */
        void setAttribute(String name, Object value);
        /**
       获取指定name的属性值,如果该属性不存在,则返回Null
       注意是BeanDefinition的属性
       */
        Object getAttribute(String name);
        /**
       删除指定name的属性值,如果找不到Nmae属性的值则返回Null
       注意是BeanDefinition的属性
       */
        Object removeAttribute(String name);
        /**
       如果属性名为name的属性存在则返回true,否者返回false
       注意是BeanDefinition的属性
       */
        boolean hasAttribute(String name);
        /**
       返回所有的属性名称
       注意是BeanDefinition的属性
         */
        String[] attributeNames();
    }

インターフェース定義は、BeanDefinition メタデータをアタッチしてアクセスするために使用されます。インターフェースは操作メソッドを定義しているだけであることがわかります。このインターフェースのメソッドは非常に単純ですが、このインターフェースが何を意味するのかはわかりません。継承図を振り返ると、このインターフェイスは、唯一の実装クラス AttributeAccessorSupport を見つけることができます。

1.1.1 実装クラスAttributeAccessorSupport

    public abstract class AttributeAccessorSupport implements AttributeAccessor, Serializable {

        /** Map with String keys and Object values. */
        //用于存放属性键值对
        private final Map<String, Object> attributes = new LinkedHashMap<>();
        
        //设置属性值 value是BeanMetadataAttribute类型
        @Override 
        public void setAttribute(String name, @Nullable Object value) {
            Assert.notNull(name, "Name must not be null");
            if (value != null) {
                this.attributes.put(name, value);
            }
            else {
                removeAttribute(name);
            }
        }
        
        //获取属性值 value是BeanMetadataAttribute类型
        @Override
        @Nullable
        public Object getAttribute(String name) {
            Assert.notNull(name, "Name must not be null");
            return this.attributes.get(name);
        }
        
        //删除属性值
        @Override
        @Nullable
        public Object removeAttribute(String name) {
            Assert.notNull(name, "Name must not be null");
            return this.attributes.remove(name);
        }
       
       //判断是否有属性值
        @Override
        public boolean hasAttribute(String name) {
            Assert.notNull(name, "Name must not be null");
            return this.attributes.containsKey(name);
        }
        
        //获取所有属性值名字
        @Override
        public String[] attributeNames() {
            return StringUtils.toStringArray(this.attributes.keySet());
        }

        //内部使用,属性值的拷贝
        /**
         * Copy the attributes from the supplied AttributeAccessor to this accessor.
         * @param source the AttributeAccessor to copy from
         */
        protected void copyAttributesFrom(AttributeAccessor source) {
            Assert.notNull(source, "Source must not be null");
            String[] attributeNames = source.attributeNames();
            for (String attributeName : attributeNames) {
                setAttribute(attributeName, source.getAttribute(attributeName));
            }
        }
        
        //重写equals方法,判断是否与别的属性类共用一个存储结构,即判断LinkedHashMap是否相等
        @Override
        public boolean equals(Object other) {
            return (this == other || (other instanceof AttributeAccessorSupport &&
                    this.attributes.equals(((AttributeAccessorSupport) other).attributes)));
        }
        @Override
        public int hashCode() {
            return this.attributes.hashCode();
        }
    }

実際、この実装クラスと BeanDefinition の関係はまだわかりません。ただし、AttributeAccessorSupport は LinkedHashMap を維持しているだけであることを明確にしておきます。このLinkedHashMapにはBeanDefinitionのいくつかの属性値が格納されていますが、それはどのような属性値なのでしょうか?以下のコードを見てください。

        public class SpringTest {
            public static void main(String[] args) throws InterruptedException {
                AnnotationConfigApplicationContext context = new    
                                            AnnotationConfigApplicationContext();
                //注册配置类
                context.register(Config.class);
                GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
                beanDefinition.setBeanClassName("com.InterService");
                //设置属性值
                beanDefinition.setAttribute("AttributeAccessor","源码之路");
                //将beanDefinition注册到spring容器中
                context.registerBeanDefinition("interService",beanDefinition);
                //加载或者刷新当前的配置信息
                context.refresh();
                //拿到属性信息
                String[] attributes = context.getBeanDefinition("interService").attributeNames();
            }
        }

interService に対応する beanDefinition の属性を表示します。

画像.png

画像.png

画像.png

ビジネス クラスを記述するために BeanDefinition が使用されることはわかっていますが、BeanDefitino を記述するのは誰でしょうか?

属性値を設定して記述します!

例えば、beanDefinitionのプロキシモード等については後述する。ここでの FULL と LITE は、エージェントを生成するかどうかの兆候です。

具体区别可参考: blog.csdn.net/tales522/ar…

1.2 BeanMetadataElement:作用是获取bd对应的class的磁盘文件位置

    public interface BeanMetadataElement {
        //获取源对象,可能返回null
        Object getSource();
     }

BeanDefinition中存了业务类在虚拟机中的class,这个上篇博文讲了。

但是这个class文件存在你电脑硬盘哪里呢?

getSource翻译成中文就是获取源,对象的源是class,那class的源就是你硬盘上的文件。看下面代码:

    public class SpringTest {
        public static void main(String[] args) throws InterruptedException {
            AnnotationConfigApplicationContext context = new    
                                                AnnotationConfigApplicationContext();
            //注册配置类
            context.register(Config.class);
            //加载或者刷新当前的配置信息
            context.refresh();
            //获取InterService.class的源
            System.out.println(context.getBeanDefinition("interService").getSource());
        }
    }

//输出:file [E:\study\spring-framework\source-code\out\production\classes\tyrant\InterService.class] 

1.2.1 实现:BeanMetadataAttributeAccessor

BeanMetadataElement接口提供了获取源的抽象方法。

真正的实现是在它的实现类BeanMetadataAttributeAccessor中。

BeanMetadataAttributeAccessor继承了AttributeAccessorSupport并且实现了BeanMetadataElement接口。

AttributeAccessorSupport实现了上面的AttributeAccessor。

我们看一下它的源码:

    public class BeanMetadataAttributeAccessor extends AttributeAccessorSupport implements BeanMetadataElement {
    
        @Nullable
        private Object source;
    
        /**
         * Set the configuration source {@code Object} for this metadata element.
         * <p>The exact type of the object will depend on the configuration mechanism used.
         * 设置源
         */
        public void setSource(@Nullable Object source) {
            this.source = source;
        }
    
        @Override
        @Nullable
        //获取源
        public Object getSource() {
            return this.source;
        }
     
        //设置属性值,如果已经存在就覆盖,不存在就添加,BeanMetadataAttribute封装了键值对
        //注意value是1个BeanMetadataAttribute
        public void addMetadataAttribute(BeanMetadataAttribute attribute) {
            //super指的是AttributeAccessorSupport
            //AttributeAccessorSupport中维护了1个LinkedHashMap用于存放BD的属性
            super.setAttribute(attribute.getName(), attribute);
        }
        
        /**
         * 根据名字获取属性键值对的封装对象BeanMetadataAttribute
         */
        @Nullable
        public BeanMetadataAttribute getMetadataAttribute(String name) {
            //super指的是AttributeAccessorSupport
            //AttributeAccessorSupport中维护了1个LinkedHashMap用于存放BD的属性
            return (BeanMetadataAttribute) super.getAttribute(name);
        }
        
        //设置属性值,name表示键,value表示值
        @Override
        public void setAttribute(String name, @Nullable Object value) {
            super.setAttribute(name, new BeanMetadataAttribute(name, value));
        }
        
        @Override
        @Nullable
        //根据键获取属性值
        public Object getAttribute(String name) {
            BeanMetadataAttribute attribute = (BeanMetadataAttribute) 
                                                        super.getAttribute(name);
            return (attribute != null ? attribute.getValue() : null);
        }
        
        @Override
        @Nullable
        //移除属性值,并返回值,不存在就返回空
        public Object removeAttribute(String name) {
            BeanMetadataAttribute attribute 
                = (BeanMetadataAttribute) super.removeAttribute(name);
            return (attribute != null ? attribute.getValue() : null);
        }
    }

BeanMetadataAttributeAccessor不但继承了AttributeAccessorSupport还实现了BeanMetadataElement,换言之,既可以操作属性值,也可以操作源。

1.2.1.1BeanMetadataAttribute

上面代码中的BeanMetadataAttribute其实就是对BeanDefinition的属性的键值对进行了封装,如下:

    public class BeanMetadataAttribute implements BeanMetadataElement {
        /**
         * 属性信息
         */
        private final String name;  // 属性名
        private final Object value; // 属性值
        
        // bd的class对应的文件位置
        private Object source;      
                                    
        /**
         * 构造器(设置属性信息)
         */
        public BeanMetadataAttribute(String name, Object value) {
            Assert.notNull(name, "Name must not be null");
            this.name = name;
            this.value = value;
        }
    
        /**
         * 获取属性名、属性值以及获取、设置属性所属对象
         */
        public String getName() {
            return this.name;
        }
        public Object getValue() {
            return this.value;
        }
        public void setSource(Object source) {
            this.source = source;
        }
        @Override
        public Object getSource() {
            return this.source;
        }
        /**
         * 判断属性是否相等
         */
        @Override
        public boolean equals(Object other) {
            if (this == other) {
                return true;
            }
            if (!(other instanceof BeanMetadataAttribute)) {
                return false;
            }
            BeanMetadataAttribute otherMa = (BeanMetadataAttribute) other;
            return (this.name.equals(otherMa.name) &&
                    ObjectUtils.nullSafeEquals(this.value, otherMa.value) &&
                    ObjectUtils.nullSafeEquals(this.source, otherMa.source));
        }
        @Override
        public int hashCode() {
            return this.name.hashCode() * 29 + ObjectUtils.nullSafeHashCode(this.value);
        }
        @Override
        public String toString() {
            return "metadata attribute '" + this.name + "'";
        }
    }

画像.png

至此,我们讲完了BeanDefinition接口、父接口、父接口实现类的源代码,BeanDefinition的实现类会继承BeanDefinition父接口的实现类。到此为止,BeanDefinition的实现类可以操作属性和源,下面讲解BeanDefinition的实现类如何实现BeanDefinition接口。

总结

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement   
BeanDefinition接口的父接口:

 1. AttributeAccessor
         1.1 实现类AttributeAccessorSupport是1个抽象类,作用是操作bd的属性,属性存放在LinkedHashMap。
         1.2 LinkedHashMap的keyString,value是BeanMetadataAttribute。
         
 2. BeanMetadataElement
         2.1 实现类BeanMetadataAttributeAccessor,作用是获取源即bd对应的class的磁盘文件位置
         2.2 实现类BeanMetadataAttributeAccessor继承了AttributeAccessorSupport既可以操作属性值,也可以操作源
         2.3 通过重写AttributeAccessorSupport抽象类的方法和BeanMetadataAttribute对象操作bd的属性。
 ***/     

一文要約: BeanDefinition 実装クラス BeanMetadataAttributeAccessor は BeanMetadataElement を実装し、AttributeAccessorSupport を継承します。ソースの設定と取得ができるほか、bd のプロパティ値の設定と取得もできます。

おすすめ

転載: juejin.im/post/7234909292447744037