【SingletonSupplier.of(Supplier<T> supplier)】

概要

今天在阅读MallChat的业务代码的时候,发现在事务模块中有个自动配置类TransactionAutoConfiguration。当中有一段代码从来没有见过,故此记录一下写法以及其中使用到的一些技术方法。

整体架构流程

附上代码

/**
     * Collect any {@link AsyncConfigurer} beans through autowiring.
     */
    @Autowired
    void setConfigurers(ObjectProvider<SecureInvokeConfigurer> configurers) {
        Supplier<SecureInvokeConfigurer> configurer = SingletonSupplier.of(() -> {
            List<SecureInvokeConfigurer> candidates = configurers.stream().collect(Collectors.toList());
            if (CollectionUtils.isEmpty(candidates)) {
                return null;
            }
            if (candidates.size() > 1) {
                throw new IllegalStateException("Only one SecureInvokeConfigurer may exist");
            }
            return candidates.get(0);
        });
        executor = Optional.ofNullable(configurer.get()).map(SecureInvokeConfigurer::getSecureInvokeExecutor).orElse(ForkJoinPool.commonPool());
    }

可以看到这个方法是设置配置使用。传入的参数ObjectProvider < SecureInvokeConfigurer > configurers为从IOC容器中获取。在方法中将参数处理赋值给executor线程池。泛型中的类为自定义接口,有且仅有一个方法,返回值为一个线程池。

public interface SecureInvokeConfigurer {

    /**
     * 返回一个线程池
     */
    @Nullable
    default Executor getSecureInvokeExecutor() {
        return null;
    }

}

查看实现发现只有一个线程池配置类实现了这个接口
在这里插入图片描述
可以看到实现getSecureInvokeExecutor方法返回了mallchatExecutor()方法。

 	@Bean(MALLCHAT_EXECUTOR)
    @Primary
    public ThreadPoolTaskExecutor mallchatExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(200);
        executor.setThreadNamePrefix("mallchat-executor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//满了调用线程执行,认为重要任务
        executor.setThreadFactory(new MyThreadFactory(executor));
        executor.initialize();
        return executor;
    }

可以看出mallchatExecutor方法就是返回了一个自定义的线程池。这个方法使用了@Primary注解,查询资料得知这个注解是用于在多个相同类型的 bean 中指定一个默认的 bean。
兜了一圈相当于最开始setConfigurers方法的参数为ioc容器中的ThreadPoolConfig配置类。
方法内主要就是使用了SingletonSupplier.of(Supplier< T> supplier)这个方法。这个方法也是头一次遇见,应该是函数式接口Supplier那边相关的方法。看类名应该是和单例有关系。
下面附上SingletonSupplier的源码。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.util.function;

import java.util.function.Supplier;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

public class SingletonSupplier<T> implements Supplier<T> {
    @Nullable
    private final Supplier<? extends T> instanceSupplier;
    @Nullable
    private final Supplier<? extends T> defaultSupplier;
    @Nullable
    private volatile T singletonInstance;

    public SingletonSupplier(@Nullable T instance, Supplier<? extends T> defaultSupplier) {
        this.instanceSupplier = null;
        this.defaultSupplier = defaultSupplier;
        this.singletonInstance = instance;
    }

    public SingletonSupplier(@Nullable Supplier<? extends T> instanceSupplier, Supplier<? extends T> defaultSupplier) {
        this.instanceSupplier = instanceSupplier;
        this.defaultSupplier = defaultSupplier;
    }

    private SingletonSupplier(Supplier<? extends T> supplier) {
        this.instanceSupplier = supplier;
        this.defaultSupplier = null;
    }

    private SingletonSupplier(T singletonInstance) {
        this.instanceSupplier = null;
        this.defaultSupplier = null;
        this.singletonInstance = singletonInstance;
    }

    @Nullable
    public T get() {
        T instance = this.singletonInstance;
        if (instance == null) {
            synchronized(this) {
                instance = this.singletonInstance;
                if (instance == null) {
                    if (this.instanceSupplier != null) {
                        instance = this.instanceSupplier.get();
                    }

                    if (instance == null && this.defaultSupplier != null) {
                        instance = this.defaultSupplier.get();
                    }

                    this.singletonInstance = instance;
                }
            }
        }

        return instance;
    }

    public T obtain() {
        T instance = this.get();
        Assert.state(instance != null, "No instance from Supplier");
        return instance;
    }

    public static <T> SingletonSupplier<T> of(T instance) {
        return new SingletonSupplier(instance);
    }

    @Nullable
    public static <T> SingletonSupplier<T> ofNullable(@Nullable T instance) {
        return instance != null ? new SingletonSupplier(instance) : null;
    }

    public static <T> SingletonSupplier<T> of(Supplier<T> supplier) {
        return new SingletonSupplier(supplier);
    }

    @Nullable
    public static <T> SingletonSupplier<T> ofNullable(@Nullable Supplier<T> supplier) {
        return supplier != null ? new SingletonSupplier(supplier) : null;
    }
}

可以看出这个类实现了Supplier接口。里面有三个属性

	@Nullable
	//包装的真正的Supplier
    private final Supplier<? extends T> instanceSupplier;
    @Nullable
    //默认的Supplier
    private final Supplier<? extends T> defaultSupplier;
    @Nullable
    //包装的实例
    private volatile T singletonInstance;

看到有两个of方法,一个参数是Supplier的,相当于把instanceSupplier传进来,一个是T的,相当于直接把实例singletonInstance传进来,然后调构造方法给属性赋值。
主要就是get()方法。可以看出逻辑主要就是DCL单例模式。

@Nullable
    public T get() {
        T instance = this.singletonInstance;
        if (instance == null) {
            synchronized(this) {
                instance = this.singletonInstance;
                if (instance == null) {
                    if (this.instanceSupplier != null) {
                        instance = this.instanceSupplier.get();
                    }

                    if (instance == null && this.defaultSupplier != null) {
                        instance = this.defaultSupplier.get();
                    }

                    this.singletonInstance = instance;
                }
            }
        }
        return instance;
    }

首先就是DCL加锁判断包装实例是否为空,不为空就直接返回实例,为空就去调用instanceSupplier的get方法将结果赋值给singletonInstance。如果singletonInstance还未空并且默认的defaultSupplier不为空就调用defaultSupplier的get方法。

小结

本质上setConfigurers方法就是获取到IOC中的ThreadPoolConfig,然后将ThreadPoolConfig中的getSecureInvokeExecutor方法返回的线程池赋值给executor。如果没有则默认使用用ForkJoinPool.commonPool()返回的线程池。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值