Отслеживание источника ObjectProvider аннотаций Spring Boot

Java

В последнее время еще учусь читать исходный код Spring Boot.В процессе задействуется много функциональных фич, которые относительно редко встречаются в повседневных проектах.Также интересно изучить это подробно.В этом тоже одна из прелестей чтение исходного кода. Напишите статью здесь и поделитесь ею со всеми.

ObjectProvider в автонастройке

При чтении конфигурации Tomcat в исходном коде автоматической конфигурации Spring Boot вы видите следующий исходный код автоматической конфигурации.

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({Servlet.class,Tomcat.class, UpgradeProtocol.class })
@ConditionalOnMissingBean(value = ServletWebServerFactory.class, search = SearchStrategy.CURRENT)
public static class EmbeddedTomcat {
    @Bean
    public TomcatServletWebServerFactory tomcatServletWebServerFactory(
            ObjectProvider<TomcatConnectorCustomizer> connectorCustomizers,
            ObjectProvider<TomcatContextCustomizer> contextCustomizers,
            ObjectProvider<TomcatProtocolHandlerCustomizer<?>> protocolHandlerCustomizers) {
        // ...
    }
}

Это обычный класс конфигурации на основе Java, поэтому вы находите, что он используется иначе, чем другие? Да, это три параметра ObjectProvider. Это также то, о чем эта статья.

Пружинный впрыск

Прежде чем знакомиться с использованием ObjectProvider, давайте рассмотрим знания, связанные с внедрением.

При использовании Spring мы можем внедрить класс в другой класс различными способами, например, с помощью аннотаций @Autowired и @Resources.

А @Autowired можно аннотировать в разных местах для достижения эффекта внедрения, например аннотацию в конструкторе:

@Service
public class FooService {
    private final FooRepository repository;
    @Autowired
    public FooService(FooRepository repository) {
        this.repository = repository
    }
}

Примечание о свойствах:

@Service
public class FooService {
    @Autowired
    private final FooRepository repository;
}

Аннотация находится в методе установки:

@Service
public class FooService {
    private final FooRepository repository;
    @Autowired
    public void setFooRepository(FooRepository repository) {
        this.repository = repository
    }
}

Новые возможности весны 4.3

Это самый распространенный способ внедрения: если вы забудете написать аннотацию @Autowired, при запуске будет выброшено исключение.

Но после весны 4.3 была введена новая функция: когда параметр конструктора является одним параметром конструктора, вы можете аннотировать с помощью @Autowired.

Следовательно, приведенный выше код можно преобразовать в следующий вид:

@Service
public class FooService {
    private final FooRepository repository;
    public FooService(FooRepository repository) {
        this.repository = repository
    }
}

Использование этой формы будет более элегантным внешним видом. Эта характеристика используется в большом количестве автоматической конфигурации класса Spring Boot.

Улучшенные зависимости

Также в Spring 4.3 неявно внедряются не только свойства параметров одиночной конструкции. Также представлен интерфейс ObjectProvider.

Интерфейс ObjectProvider — это расширение интерфейса ObjectFactory, специально разработанное для точек внедрения, что делает внедрение более простым и необязательным.

Итак, когда использовать интерфейс ObjectProvider?

Если Bean, который должен быть введен с параметрами, пуст или имеет более одного, настало время для ObjectProvider вступить в игру.

Если внедренный экземпляр пуст, использование ObjectProvider позволяет избежать исключения зависимых объектов, вызванных сильными зависимостями; если экземпляров несколько, метод ObjectProvider получит bean-компонент в соответствии с порядком, заданным интерфейсом Ordered, реализованным bean-компонентом, или @ Заказать аннотацию. Это обеспечивает более расслабленный способ внедрения зависимостей.

После Spring 5.1 для получения упорядоченного метода Stream предоставляется метод orderStream, основанный на Stream.

После использования ObjectProvider приведенный выше код становится следующим:

@Service
public class FooService {
    private final FooRepository repository;
    public FooService(ObjectProvider<FooRepository> repositoryProvider) {
        this.repository = repositoryProvider.getIfUnique();
    }
}

Преимущество этого очевидно, когда в контейнере нет FooRepository или их больше одного, с этим можно справиться спокойно. Но недостаток также очевиден, если FooRepository не может быть нулевым, он может перенести исключение из фазы запуска в фазу бизнес-операций.

Исходный код ObjectProvider

Исходный код и анализ ObjectProvider следующие:

public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {

    // 返回指定类型的bean, 如果容器中不存在, 抛出NoSuchBeanDefinitionException异常
    // 如果容器中有多个此类型的bean, 抛出NoUniqueBeanDefinitionException异常
    T getObject(Object... args) throws BeansException;

    // 如果指定类型的bean注册到容器中, 返回 bean 实例, 否则返回 null
    @Nullable
    T getIfAvailable() throws BeansException;

    // 如果返回对象不存在,则进行回调,回调对象由Supplier传入
    default T getIfAvailable(Supplier<T> defaultSupplier) throws BeansException {
        T dependency = getIfAvailable();
        return (dependency != null ? dependency : defaultSupplier.get());
    }

     // 消费对象的一个实例(可能是共享的或独立的),如果存在通过Consumer回调消耗目标对象。
    default void ifAvailable(Consumer<T> dependencyConsumer) throws BeansException {
        T dependency = getIfAvailable();
        if (dependency != null) {
            dependencyConsumer.accept(dependency);
        }
    }

    // 如果不可用或不唯一(没有指定primary)则返回null。否则,返回对象。
    @Nullable
    T getIfUnique() throws BeansException;

    // 如果存在唯一对象,则调用Supplier的回调函数
    default T getIfUnique(Supplier<T> defaultSupplier) throws BeansException {
        T dependency = getIfUnique();
        return (dependency != null ? dependency : defaultSupplier.get());
    }

    // 如果存在唯一对象,则消耗掉该对象
    default void ifUnique(Consumer<T> dependencyConsumer) throws BeansException {
        T dependency = getIfUnique();
        if (dependency != null) {
            dependencyConsumer.accept(dependency);
        }
    }

    // 返回符合条件的对象的Iterator,没有特殊顺序保证(一般为注册顺序)
    @Override
    default Iterator<T> iterator() {
        return stream().iterator();
    }

    // 返回符合条件对象的连续的Stream,没有特殊顺序保证(一般为注册顺序)
    default Stream<T> stream() {
        throw new UnsupportedOperationException("Multi element access not supported");
    }

    // 返回符合条件对象的连续的Stream。在标注Spring应用上下文中采用@Order注解或实现Order接口的顺序
    default Stream<T> orderedStream() {
        throw new UnsupportedOperationException("Ordered element access not supported");
    }
}

Среди них этот интерфейс также используется в BeanFactory для определения возвращаемого значения метода:

public interface BeanFactory {

    <T> ObjectProvider<T> getBeanProvider(Class<T> requiredType);
    <T> ObjectProvider<T> getBeanProvider(ResolvableType requiredType);
    ...
}

На данный момент использование ObjectProvider и анализ исходного кода завершены.

Оригинальная ссылка: "OBJECTPROVIDER отслеживание источника аннотаций SPRING BOOT


Программа Новые Горизонты: Захватывающие и растущие нельзя пропустить

程序新视界-微信公众号