Как реализовать собственную автоконфигурацию SpringBoot

Spring Boot

Основы SpringBoot

SpringBootможет помочь нам лучше использоватьSpring, быстрее настроить работающее приложение Spring.

SpringBootЗапись, реализующая автоматическую настройку,@EnableAutoConfigurationАннотация, которая в свою очередь проходит@ImportАннотации импортируютсяAutoConfigurationImportSelector, в этом классе реализуетсяMETA-INF/spring.factoriesсерединаorg.springframework.boot.autoconfigure.EnableAutoConfigurationВсе конфигурации, заданные свойствами, такими какorg.springframework.boot.autoconfigure.cache.CacheAutoConfiguration.

//文件:spring-boot-autoconfigure-2.1.3.RELEASE.jar!/META-INF/spring.factories

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\

В CacheAutoConfiguration через условную аннотацию@ConditionalOnXXX,а также@ImportАннотация для достижения корреляции функции кешаBeanавтоматическая конфигурация.

// 文件:spring-boot-autoconfigure-2.1.3.RELEASE-sources.jar!/org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.java

@Configuration
@ConditionalOnClass(CacheManager.class)
@ConditionalOnBean(CacheAspectSupport.class)
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
@EnableConfigurationProperties(CacheProperties.class)
@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, HazelcastAutoConfiguration.class,
		HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })
@Import(CacheConfigurationImportSelector.class)
public class CacheAutoConfiguration {

	@Bean
	@ConditionalOnMissingBean
	public CacheManagerCustomizers cacheManagerCustomizers(
			ObjectProvider<CacheManagerCustomizer<?>> customizers) {
		return new CacheManagerCustomizers(
				customizers.orderedStream().collect(Collectors.toList()));
	}

Реализуйте свою собственную автоконфигурацию

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

Шаг 1. Внедрение официальных зависимостей Spring

POM-файл проекта:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
    <!-- 和Spring官方的自动配置做区分 -->
	<groupId>geektime.spring.hello</groupId>
	<artifactId>geektime-spring-boot-autoconfigure</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>geektime-spring-boot-autoconfigure</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
		<spring-boot.version>2.1.3.RELEASE</spring-boot.version>
	</properties>

     <!-- 引入Spring官方的配置管理 -->
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-dependencies</artifactId>
				<version>${spring-boot.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<dependencies>
         <!-- 引入SpringBoot的自动配置模块 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-autoconfigure</artifactId>
		</dependency>

        <!-- 自己的定义第三方依赖 -->
		<dependency>
			<groupId>geektime.spring.hello</groupId>
			<artifactId>greeting</artifactId>
			<version>0.0.1-SNAPSHOT</version>
			<scope>provided</scope>
		</dependency>
	</dependencies>

</project>

Шаг 2: Напишите конфигурацию Java и добавьте условные аннотации

Условные аннотации, поддерживаемые Spring:

  • Условная аннотация @Conditional
  • Условие класса @ConditionalOnClass, @ConditionalOnMissingClass
  • Условие свойства @ConditionalOnProperty
  • Условия компонента @ConditionalOnBean, @ConditionalOnMissingBean, @ConditionalOnSingleCandidate
  • Состояние ресурса @ConditionalOnResource
  • Условия использования веб-приложений @ Условие.
  • Другие условия @ConditionalOnExpression, @ConditionalOnJava, @ConditionalOnJndi

Код конфигурации Java выглядит следующим образом:

@Configuration
@ConditionalOnClass(GreetingApplicationRunner.class)
public class GreetingAutoConfiguration {
    @Bean
    @ConditionalOnMissingBean(GreetingApplicationRunner.class)
    @ConditionalOnProperty(name = "greeting.enabled", havingValue = "true", matchIfMissing = true)
    public GreetingApplicationRunner greetingApplicationRunner() {
        return new GreetingApplicationRunner();
    }
}

Шаг 3: Автоматическая настройка позиционирования

в текущем проектеresourceв каталогеMETA-INFСоздан в каталогеspring.factoriesфайл со следующим содержимым:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
geektime.spring.hello.greeting.GreetingAutoConfiguration

Шаг 4: Определите порядок выполнения автоконфигурации

Основные аннотации:

  • @AutoConfigureBefore
  • @AutoConfigureAfter
  • @AutoConfigureOrder

Обычно не требуется, пожалуйста, обратитесь к конкретному использованиюSpring официальная автоматическая конфигурация.

Как реализовать SpringBoot в старых версиях Spring, которые не поддерживают SpringBoot

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

Добавьте конфигурацию:

@Configuration
public class GreetingAutoConfiguration {
    @Bean
    public static GreetingBeanFactoryPostProcessor greetingBeanFactoryPostProcessor() {
        return new GreetingBeanFactoryPostProcessor();
    }
}

пользовательскийBeanFactoryPostProcessorРеализуйте функции, аналогичные условным аннотациям:

@Slf4j
public class GreetingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        boolean hasClass = ClassUtils.isPresent("geektime.spring.hello.greeting.GreetingApplicationRunner",
                GreetingBeanFactoryPostProcessor.class.getClassLoader());
        if (!hasClass) {
            log.info("GreetingApplicationRunner is NOT present in CLASSPATH.");
            return;
        }

        if (beanFactory.containsBeanDefinition("greetingApplicationRunner")) {
            log.info("We already have a greetingApplicationRunner bean registered.");
            return;
        }

        register(beanFactory);
    }

    private void register(ConfigurableListableBeanFactory beanFactory) {
        if (beanFactory instanceof BeanDefinitionRegistry) {
            GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
            beanDefinition.setBeanClass(GreetingApplicationRunner.class);

            ((BeanDefinitionRegistry) beanFactory)
                    .registerBeanDefinition("greetingApplicationRunner",
                            beanDefinition);
        } else {
            beanFactory.registerSingleton("greetingApplicationRunner",
                    new GreetingApplicationRunner());
        }
    }
}

использованная литература

  1. Точки расширения Spring Framework
  2. Видеокурс Spring Boot of the Spring Family Bucket
  3. Код курса Spring Family Bucket