Spring IOC源码解析(02)PropertySource和PropertySources

PropertySource

PropertySource主要是对属性源的抽象,抽象除了熟悉源名称和属性源内容对象。其主要方法仍然是对这两个字段进行操作。

public abstract class PropertySource<T> {

    protected final Log logger = LogFactory.getLog(getClass());

    protected final String name;

    protected final T source;


    /**
     * 构造器
     */
    public PropertySource(String name, T source) {
        Assert.hasText(name, "Property source name must contain at least one character");
        Assert.notNull(source, "Property source must not be null");
        this.name = name;
        this.source = source;
    }

    /**
     * 不带source的构造器
     */
    @SuppressWarnings("unchecked")
    public PropertySource(String name) {
        this(name, (T) new Object());
    }


    /**
     * 获取name字段
     */
    public String getName() {
        return this.name;
    }

    /**
     * 获取source字段
     */
    public T getSource() {
        return this.source;
    }

    /**
     * 是否包含属性
     */
    public boolean containsProperty(String name) {
        return (getProperty(name) != null);
    }

    /**
     * 获取属性值
     */
    @Nullable
    public abstract Object getProperty(String name);


    /**
     * 两个属性源对象是否相同,仅比较名称
     */
    @Override
    public boolean equals(@Nullable Object other) {
        return (this == other || (other instanceof PropertySource &&
                ObjectUtils.nullSafeEquals(this.name, ((PropertySource<?>) other).name)));
    }

    /**
     * 根据名称生成hash码
     */
    @Override
    public int hashCode() {
        return ObjectUtils.nullSafeHashCode(this.name);
    }

    /**
     * 重写的toString方法
     */
    @Override
    public String toString() {
        if (logger.isDebugEnabled()) {
            return getClass().getSimpleName() + "@" + System.identityHashCode(this) +
                    " {name='" + this.name + "', properties=" + this.source + "}";
        }
        else {
            return getClass().getSimpleName() + " {name='" + this.name + "'}";
        }
    }


    /**
     * 生成一个仅比较的属性源对象,不可用获取name和source
     */
    public static PropertySource<?> named(String name) {
        return new ComparisonPropertySource(name);
    }


    /**
     * 存根属性源类,主要用在测试场景
     */
    public static class StubPropertySource extends PropertySource<Object> {

        public StubPropertySource(String name) {
            super(name, new Object());
        }

        /**
         * Always returns {@code null}.
         */
        @Override
        @Nullable
        public String getProperty(String name) {
            return null;
        }
    }


    /**
     * 可比较的属性源类,仅用作根据名称进行比较的场景
     */
    static class ComparisonPropertySource extends StubPropertySource {

        private static final String USAGE_ERROR =
                "ComparisonPropertySource instances are for use with collection comparison only";

        public ComparisonPropertySource(String name) {
            super(name);
        }

        @Override
        public Object getSource() {
            throw new UnsupportedOperationException(USAGE_ERROR);
        }

        @Override
        public boolean containsProperty(String name) {
            throw new UnsupportedOperationException(USAGE_ERROR);
        }

        @Override
        @Nullable
        public String getProperty(String name) {
            throw new UnsupportedOperationException(USAGE_ERROR);
        }
    }
}

PropertiesPropertySource

属性源抽象类有很多子类的实现,我们仅仅分析其中最常用的一个,即:PropertiesPropertySource

其继承关系如下:

PropertiesPropertySource -> MapPropertySource -> EnumerablePropertySource -> PropertySource

逐层分析如下:

public abstract class EnumerablePropertySource<T> extends PropertySource<T> {

    public EnumerablePropertySource(String name, T source) {
        super(name, source);
    }

    protected EnumerablePropertySource(String name) {
        super(name);
    }


    /**
     * 属性名称是否存在
     */
    @Override
    public boolean containsProperty(String name) {
        return ObjectUtils.containsElement(getPropertyNames(), name);
    }

    /**
     * 获取所有的熟悉名称
     */
    public abstract String[] getPropertyNames();
}
public class MapPropertySource extends EnumerablePropertySource<Map<String, Object>> {

    // source为Map对象
    public MapPropertySource(String name, Map<String, Object> source) {
        super(name, source);
    }

    // 在Map对象中获取指定name对应的值
    @Override
    @Nullable
    public Object getProperty(String name) {
        return this.source.get(name);
    }
    
    // 是否包含某属性,重写了`EnumerablePropertySource`的此方法,目的是为了提升查询的效率
    @Override
    public boolean containsProperty(String name) {
        return this.source.containsKey(name);
    }

    // 获取熟悉名称数组
    @Override
    public String[] getPropertyNames() {
        return StringUtils.toStringArray(this.source.keySet());
    }
}
// 和`MapPropertySource`没太大区别,唯一的操作就是对source进行了加锁,从而避免并发场景下的线程不安全因素。
public class PropertiesPropertySource extends MapPropertySource {

    @SuppressWarnings({"rawtypes", "unchecked"})
    public PropertiesPropertySource(String name, Properties source) {
        super(name, (Map) source);
    }

    protected PropertiesPropertySource(String name, Map<String, Object> source) {
        super(name, source);
    }


    @Override
    public String[] getPropertyNames() {
        synchronized (this.source) {
            return super.getPropertyNames();
        }
    }
}

PropertySource

PropertySource主要是对属性源的抽象,抽象除了熟悉源名称和属性源内容对象。其主要方法仍然是对这两个字段进行操作。

public abstract class PropertySource<T> {

    protected final Log logger = LogFactory.getLog(getClass());

    protected final String name;

    protected final T source;


    /**
     * 构造器
     */
    public PropertySource(String name, T source) {
        Assert.hasText(name, "Property source name must contain at least one character");
        Assert.notNull(source, "Property source must not be null");
        this.name = name;
        this.source = source;
    }

    /**
     * 不带source的构造器
     */
    @SuppressWarnings("unchecked")
    public PropertySource(String name) {
        this(name, (T) new Object());
    }


    /**
     * 获取name字段
     */
    public String getName() {
        return this.name;
    }

    /**
     * 获取source字段
     */
    public T getSource() {
        return this.source;
    }

    /**
     * 是否包含属性
     */
    public boolean containsProperty(String name) {
        return (getProperty(name) != null);
    }

    /**
     * 获取属性值
     */
    @Nullable
    public abstract Object getProperty(String name);


    /**
     * 两个属性源对象是否相同,仅比较名称
     */
    @Override
    public boolean equals(@Nullable Object other) {
        return (this == other || (other instanceof PropertySource &&
                ObjectUtils.nullSafeEquals(this.name, ((PropertySource<?>) other).name)));
    }

    /**
     * 根据名称生成hash码
     */
    @Override
    public int hashCode() {
        return ObjectUtils.nullSafeHashCode(this.name);
    }

    /**
     * 重写的toString方法
     */
    @Override
    public String toString() {
        if (logger.isDebugEnabled()) {
            return getClass().getSimpleName() + "@" + System.identityHashCode(this) +
                    " {name='" + this.name + "', properties=" + this.source + "}";
        }
        else {
            return getClass().getSimpleName() + " {name='" + this.name + "'}";
        }
    }


    /**
     * 生成一个仅比较的属性源对象,不可用获取name和source
     */
    public static PropertySource<?> named(String name) {
        return new ComparisonPropertySource(name);
    }


    /**
     * 存根属性源类,主要用在测试场景
     */
    public static class StubPropertySource extends PropertySource<Object> {

        public StubPropertySource(String name) {
            super(name, new Object());
        }

        /**
         * Always returns {@code null}.
         */
        @Override
        @Nullable
        public String getProperty(String name) {
            return null;
        }
    }


    /**
     * 可比较的属性源类,仅用作根据名称进行比较的场景
     */
    static class ComparisonPropertySource extends StubPropertySource {

        private static final String USAGE_ERROR =
                "ComparisonPropertySource instances are for use with collection comparison only";

        public ComparisonPropertySource(String name) {
            super(name);
        }

        @Override
        public Object getSource() {
            throw new UnsupportedOperationException(USAGE_ERROR);
        }

        @Override
        public boolean containsProperty(String name) {
            throw new UnsupportedOperationException(USAGE_ERROR);
        }

        @Override
        @Nullable
        public String getProperty(String name) {
            throw new UnsupportedOperationException(USAGE_ERROR);
        }
    }
}

PropertiesPropertySource

属性源抽象类有很多子类的实现,我们仅仅分析其中最常用的一个,即:PropertiesPropertySource

其继承关系如下:

PropertiesPropertySource -> MapPropertySource -> EnumerablePropertySource -> PropertySource

逐层分析如下:

public abstract class EnumerablePropertySource<T> extends PropertySource<T> {

    public EnumerablePropertySource(String name, T source) {
        super(name, source);
    }

    protected EnumerablePropertySource(String name) {
        super(name);
    }


    /**
     * 属性名称是否存在
     */
    @Override
    public boolean containsProperty(String name) {
        return ObjectUtils.containsElement(getPropertyNames(), name);
    }

    /**
     * 获取所有的熟悉名称
     */
    public abstract String[] getPropertyNames();
}
public class MapPropertySource extends EnumerablePropertySource<Map<String, Object>> {

    // source为Map对象
    public MapPropertySource(String name, Map<String, Object> source) {
        super(name, source);
    }

    // 在Map对象中获取指定name对应的值
    @Override
    @Nullable
    public Object getProperty(String name) {
        return this.source.get(name);
    }
    
    // 是否包含某属性,重写了`EnumerablePropertySource`的此方法,目的是为了提升查询的效率
    @Override
    public boolean containsProperty(String name) {
        return this.source.containsKey(name);
    }

    // 获取熟悉名称数组
    @Override
    public String[] getPropertyNames() {
        return StringUtils.toStringArray(this.source.keySet());
    }
}
// 和`MapPropertySource`没太大区别,唯一的操作就是对source进行了加锁,从而避免并发场景下的线程不安全因素。
public class PropertiesPropertySource extends MapPropertySource {

    @SuppressWarnings({"rawtypes", "unchecked"})
    public PropertiesPropertySource(String name, Properties source) {
        super(name, (Map) source);
    }

    protected PropertiesPropertySource(String name, Map<String, Object> source) {
        super(name, source);
    }


    @Override
    public String[] getPropertyNames() {
        synchronized (this.source) {
            return super.getPropertyNames();
        }
    }
}

PropertySources

PropertySources是对属性源列表操作的封装。主要加入了迭代器可变性集合操作。这个类有一个唯一的子类,即:MutablePropertySources

// 在迭代器的基础上,增加了判断属性源是否存在,以及根据属性源名称获取属性源的操作。
public interface PropertySources extends Iterable<PropertySource<?>> {

    /**
     * Return a sequential {@link Stream} containing the property sources.
     * @since 5.1
     */
    default Stream<PropertySource<?>> stream() {
        return StreamSupport.stream(spliterator(), false);
    }

    /**
     * Return whether a property source with the given name is contained.
     * @param name the {@linkplain PropertySource#getName() name of the property source} to find
     */
    boolean contains(String name);

    /**
     * Return the property source with the given name, {@code null} if not found.
     * @param name the {@linkplain PropertySource#getName() name of the property source} to find
     */
    @Nullable
    PropertySource<?> get(String name);
}

MutablePropertySources

MutablePropertySourcesPropertySources的基础上,增加了可变性集合操作

public class MutablePropertySources implements PropertySources {

    // 使用`CopyOnWriteArrayList`,保持集合操作的线程安全性。
    private final List<PropertySource<?>> propertySourceList = new CopyOnWriteArrayList<>();


    /**
     * 构造空集合
     */
    public MutablePropertySources() {
    }

    /**
     * 构造指定集合
     */
    public MutablePropertySources(PropertySources propertySources) {
        this();
        for (PropertySource<?> propertySource : propertySources) {
            addLast(propertySource);
        }
    }

    // ******
    // 以下所有方法都是集合操作,主要包括:
    // 增、删、改、查、替换、断言存在性等操作
    // 非常简单
    // ******
    @Override
    public Iterator<PropertySource<?>> iterator() {
        return this.propertySourceList.iterator();
    }

    @Override
    public Spliterator<PropertySource<?>> spliterator() {
        return Spliterators.spliterator(this.propertySourceList, 0);
    }

    @Override
    public Stream<PropertySource<?>> stream() {
        return this.propertySourceList.stream();
    }

    @Override
    public boolean contains(String name) {
        return this.propertySourceList.contains(PropertySource.named(name));
    }

    @Override
    @Nullable
    public PropertySource<?> get(String name) {
        int index = this.propertySourceList.indexOf(PropertySource.named(name));
        return (index != -1 ? this.propertySourceList.get(index) : null);
    }


    /**
     * Add the given property source object with highest precedence.
     */
    public void addFirst(PropertySource<?> propertySource) {
        removeIfPresent(propertySource);
        this.propertySourceList.add(0, propertySource);
    }

    /**
     * Add the given property source object with lowest precedence.
     */
    public void addLast(PropertySource<?> propertySource) {
        removeIfPresent(propertySource);
        this.propertySourceList.add(propertySource);
    }

    /**
     * Add the given property source object with precedence immediately higher
     * than the named relative property source.
     */
    public void addBefore(String relativePropertySourceName, PropertySource<?> propertySource) {
        assertLegalRelativeAddition(relativePropertySourceName, propertySource);
        removeIfPresent(propertySource);
        int index = assertPresentAndGetIndex(relativePropertySourceName);
        addAtIndex(index, propertySource);
    }

    /**
     * Add the given property source object with precedence immediately lower
     * than the named relative property source.
     */
    public void addAfter(String relativePropertySourceName, PropertySource<?> propertySource) {
        assertLegalRelativeAddition(relativePropertySourceName, propertySource);
        removeIfPresent(propertySource);
        int index = assertPresentAndGetIndex(relativePropertySourceName);
        addAtIndex(index + 1, propertySource);
    }

    /**
     * Return the precedence of the given property source, {@code -1} if not found.
     */
    public int precedenceOf(PropertySource<?> propertySource) {
        return this.propertySourceList.indexOf(propertySource);
    }

    /**
     * Remove and return the property source with the given name, {@code null} if not found.
     * @param name the name of the property source to find and remove
     */
    @Nullable
    public PropertySource<?> remove(String name) {
        int index = this.propertySourceList.indexOf(PropertySource.named(name));
        return (index != -1 ? this.propertySourceList.remove(index) : null);
    }

    /**
     * Replace the property source with the given name with the given property source object.
     * @param name the name of the property source to find and replace
     * @param propertySource the replacement property source
     * @throws IllegalArgumentException if no property source with the given name is present
     * @see #contains
     */
    public void replace(String name, PropertySource<?> propertySource) {
        int index = assertPresentAndGetIndex(name);
        this.propertySourceList.set(index, propertySource);
    }

    /**
     * Return the number of {@link PropertySource} objects contained.
     */
    public int size() {
        return this.propertySourceList.size();
    }

    @Override
    public String toString() {
        return this.propertySourceList.toString();
    }

    /**
     * Ensure that the given property source is not being added relative to itself.
     */
    protected void assertLegalRelativeAddition(String relativePropertySourceName, PropertySource<?> propertySource) {
        String newPropertySourceName = propertySource.getName();
        if (relativePropertySourceName.equals(newPropertySourceName)) {
            throw new IllegalArgumentException(
                    "PropertySource named '" + newPropertySourceName + "' cannot be added relative to itself");
        }
    }

    /**
     * Remove the given property source if it is present.
     */
    protected void removeIfPresent(PropertySource<?> propertySource) {
        this.propertySourceList.remove(propertySource);
    }

    /**
     * Add the given property source at a particular index in the list.
     */
    private void addAtIndex(int index, PropertySource<?> propertySource) {
        removeIfPresent(propertySource);
        this.propertySourceList.add(index, propertySource);
    }

    /**
     * Assert that the named property source is present and return its index.
     * @param name {@linkplain PropertySource#getName() name of the property source} to find
     * @throws IllegalArgumentException if the named property source is not present
     */
    private int assertPresentAndGetIndex(String name) {
        int index = this.propertySourceList.indexOf(PropertySource.named(name));
        if (index == -1) {
            throw new IllegalArgumentException("PropertySource named '" + name + "' does not exist");
        }
        return index;
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342