spring boot 排除自动装配的类(隐式,无代码入侵适用于工具包的开发)

spring boot 排除自动装配的类(隐式,无代码入侵适用于工具包的开发),第1张

spring boot 排除自动装配的类(隐式)
  • 1.自动装配简述
  • 2.如何排除自动装配功能
    • 2.1启动类注解设置需要排除的自动装配类
    • 2.2在配置文件中指定需要排除的类
  • 3.问题描述和寻找方案
  • 4.解决方案

1.自动装配简述

spring boot中一个重要功能就是自动装配。简单来说就是:在我们开发的项目中,引入相关功能的jar包。spring boot会将其功能自动注入进来,不需要额外的配置。当然,这是因为配置提供了很多比较公用的缺省值。举例spring boot项目中加入如下依赖,即可使项目接入本地启动的redis。这就是因为有着自动装配。

<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-data-redisartifactId>
dependency>
2.如何排除自动装配功能

有些场景下我们可能需要加入相关依赖,但是又不一定用到自动装配。面对这种情况,主要提供了两种办法。

2.1启动类注解设置需要排除的自动装配类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class SysApplication {

    public static void main(String[] args) {
        SpringApplication.run(SysApplication.class, args);
    }
}

如果项目没有直接引用依赖的话,可以使用注解的excludeName属性,传入类的全名。
EnableAutoConfiguration注解同理。

2.2在配置文件中指定需要排除的类
spring.autoconfigure.exclude = org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
# 或者这样
spring.autoconfigure.exclude[0] = org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

如果这两种方式满足的话,下面可以不看了。

3.问题描述和寻找方案

最近工作中遇到了上面两种方法不能解决的情况。大概场景是这样的:
我负责公司内部开发框架的开发。现在提供一个数据源的功能包,因为一些情况。不能让项目引入就直接使用,而是希望通过注解的形式开启使用。
所以希望引入内部开发框架中依赖的时候不带入自动装配的内容。希望做到的就是一个依赖+一个注解开启使用。额外的什么排除自动装配之类,全部封装在这个数据源的功能包中。

上代码:这里是org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationEntry的内容

	protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
		if (!isEnabled(annotationMetadata)) {
			return EMPTY_ENTRY;
		}
		AnnotationAttributes attributes = getAttributes(annotationMetadata);
		// 这里获取到了所有需要自动装配的类
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
		configurations = removeDuplicates(configurations);
		// 重点在这里,这里获取需要排除集合
		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
		checkExcludedClasses(configurations, exclusions);
		configurations.removeAll(exclusions);
		configurations = getConfigurationClassFilter().filter(configurations);
		fireAutoConfigurationImportEvents(configurations, exclusions);
		return new AutoConfigurationEntry(configurations, exclusions);
	}

这里是org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getExclusions

protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
		Set<String> excluded = new LinkedHashSet<>();
		// 这里两行获取到了启动类上指定的exclude和excludeName,也就是2.1描述的方式
		excluded.addAll(asList(attributes, "exclude"));
		excluded.addAll(Arrays.asList(attributes.getStringArray("excludeName")));
		// 这里读取配置文件中spring.autoconfigure.exclude的信息,也就是2.2描述的方式
		excluded.addAll(getExcludeAutoConfigurationsProperty());
		return excluded;
	}
4.解决方案

通过自动装配的源码发现,好像也就是这两种方式。分析一下:启动类的方式是依赖于编码的,不容易在这里动态加东西。最好还是通过动态修改配置文件。
整体思路:

  1. 获取到原配置文件内容
  2. 增加需要排除的类
  3. 保存新的高优先级配置文件

工具包代码:
resources/META-INF/spring.factories

org.springframework.boot.env.EnvironmentPostProcessor=\
    com.dong.common.data.init.ExcludeEnvironmentPostProcessor

ExcludeEnvironmentPostProcessor类

import cn.hutool.core.collection.CollectionUtil;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertiesPropertySource;

import java.util.*;

@Configuration
public class ExcludeEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered {
    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
    	
        String key = "spring.autoconfigure.exclude";
        Binder binder = Binder.get(environment);
        List<String> exList = new ArrayList<>();
        // 1 先获取到原配置文件的信息。这里参考的AutoConfigurationImportSelector#getExcludeAutoConfigurationsProperty
        List<String> stringList = (List)binder.bind(key, String[].class).map(Arrays::asList).orElse(Collections.emptyList());
        exList.addAll(stringList);
        // 2 增加需要排除的类
        exList.add("org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration");
        MutablePropertySources m = environment.getPropertySources();
        Properties p = new Properties();
        p.put(key, CollectionUtil.join(exList,","));
        // 3 保存新的配置文件
        m.addFirst(new PropertiesPropertySource("commonDataProperties", p));
    }

    @Override
    public int getOrder() {
        return Ordered.LOWEST_PRECEDENCE;
    }

用到的其他依赖

<dependency>
	<groupId>cn.hutoolgroupId>
	<artifactId>hutool-allartifactId>
	<version>5.7.3version>
dependency>

好了,大功告成。工具包中加入这些代码,会自动排除DataSourceAutoConfiguration的自动装配。最后在需要的地方再引入一下DataSourceAutoConfiguration就可以了

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/733859.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-27
下一篇 2022-04-27

发表评论

登录后才能评论

评论列表(0条)

保存