SpringBoot 扩展机制 ——Spring.factories文件 如何将外部项目加入Spring容器

SpringBoot 扩展机制 ——Spring.factories文件 如何将外部项目加入Spring容器

▶ 简介

简单说用于模块之间解耦,外部项目下各种配置、类加入到Spring容器中进行管理,类似JAVA中SPI机制。机制自行百度。

▶ 方式

将外部类引入IOC容器两种方式

1.@import

2.加入Spring.factories文件 — 主讲这个

▶ Spring.factories文件

1.在resource目录下 META-INF/ Spring.factories 文件

2.格式:自定义需要扫描到类(接口),多个用 ”,\“ 隔开

3.SpringFactoriesLoader类会去扫描加载文件下定义类,加入容器

	org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  	com.mostsnails.common.base.utils.config.WebLogAutoConfiguration,\
  	com.mostsnails.common.base.utils.config.RedisAutoConfiguration,\
  	com.mostsnails.common.base.utils.test.TestClass

注意这里使用EnableAutoConfiguration ,SpringBoot启动类@SpringBootApplication注解包下有@EnableAutoConfiguration和@Component 具体作用开启自动装备,将满足条件@Configuration配置加入到SpringBoot中。

Spring.factories也可以包含其他类型

	# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
	....

可以去看项目下spring-boot-***-start jar包

外部项目下Redis配置类

/**
 * Redis配置
 *
 * @Author MostSnails
 * @Version 1.0
 */
@Configurable
public class RedisAutoConfiguration {
    private static org.slf4j.Logger log = LoggerFactory.getLogger(RedisAutoConfiguration.class);

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
        // 创建RedisTemplate对象
        RedisTemplate template = new RedisTemplate<>();
        // 配置连接工厂
        template.setConnectionFactory(factory);
        // 定义Jackson2JsonRedisSerializer序列化对象
        Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会报异常
        om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        jacksonSeial.setObjectMapper(om);
        StringRedisSerializer stringSerial = new StringRedisSerializer();
        // redis key 序列化方式使用stringSerial
        template.setKeySerializer(stringSerial);
        // redis value 序列化方式使用jackson
        template.setValueSerializer(jacksonSeial);
        // redis hash key 序列化方式使用stringSerial
        template.setHashKeySerializer(stringSerial);
        // redis hash value 序列化方式使用jackson
        template.setHashValueSerializer(jacksonSeial);
        template.afterPropertiesSet();
        return template;
    }

    /**
     * 配置redis默认缓存管理器
     * 可以设置多个 缓存管理器 @Primary 指定默认
     */
    @Bean
    public CacheManager cacheManager(RedisTemplate template) {
        RedisCacheConfiguration defaultCacheConfiguration =
                RedisCacheConfiguration
                        .defaultCacheConfig()
                        // 设置key为String
                      .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getStringSerializer()))
                        // 设置value 为自动转Json的Object
                        .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(template.getValueSerializer()))
                        // 不缓存null
                        .disableCachingNullValues()
                        // 缓存数据保存1小时
                        .entryTtl(Duration.ofHours(1));
        RedisCacheManager redisCacheManager =
                RedisCacheManager.RedisCacheManagerBuilder
                        // Redis 连接工厂
                        .fromConnectionFactory(template.getConnectionFactory())
                        // 缓存配置
                        .cacheDefaults(defaultCacheConfiguration)
                        // 配置同步修改或删除 put/evict
                        .transactionAware()
                        .build();
        return redisCacheManager;
    }

    @Bean
    public RedisUtils redisUtils(StringRedisTemplate stringRedisTemplate) {
        log.info("Redis工具类.....Start");
        return new RedisUtils(stringRedisTemplate);
    }
}
 
  

SpringBoot 扩展机制 ——Spring.factories文件 如何将外部项目加入Spring容器_第1张图片

SpringBoot 扩展机制 ——Spring.factories文件 如何将外部项目加入Spring容器_第2张图片

SpringBoot 扩展机制 ——Spring.factories文件 如何将外部项目加入Spring容器_第3张图片

▶ 延伸扩展 — 选择性加载@Conditional 和 @ConditionalOn***

在一些自动装配配置类中 出现过 @ConditionalOn***,@EnableAutoConfiguration会在满足条件情况下加入IOC容器

/**
 * Web日志加入Spring容器
 *
 * @Author MostSnails
 * @Version 1.0
 */
public class WebLogAutoConfiguration {
    private static org.slf4j.Logger log = LoggerFactory.getLogger(WebLogAutoConfiguration.class);

    public WebLogAutoConfiguration() {
        log.info("Web日志记录配置类.....Start");
    }

    @Bean
    @ConditionalOnWebApplication//当项目是一个Web项目时进行实例化
    @ConditionalOnMissingBean(WebLogAspect.class)//当容器里没有指定Bean的条件下进行实例化。
    public WebLogAspect webLogAspect() {
        log.info("注入webLogAspect类.....");
        return new WebLogAspect();
    }
}

▶ 更多@Conditional 注解

@ConditionalOnBean:		仅仅在当前上下文中存在某个对象时,才会实例化一个Bean。
@ConditionalOnClass:	某个class位于类路径上,才会实例化一个Bean。
@ConditionalOnExpression:当表达式为true的时候,才会实例化一个Bean。
@ConditionalOnMissingBean:仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean。
@ConditionalOnMissingClass:某个class类路径上不存在的时候,才会实例化一个Bean。
@ConditionalOnNotWebApplication:不是web应用,才会实例化一个Bean。
@ConditionalOnBean:		当容器中有指定Bean的条件下进行实例化。
@ConditionalOnMissingBean:当容器里没有指定Bean的条件下进行实例化。
@ConditionalOnClass:	当classpath类路径下有指定类的条件下进行实例化。
@ConditionalOnMissingClass:当类路径下没有指定类的条件下进行实例化。
@ConditionalOnWebApplication:当项目是一个Web项目时进行实例化。
@ConditionalOnNotWebApplication:当项目不是一个Web项目时进行实例化。
@ConditionalOnProperty:	当指定的属性有指定的值时进行实例化。
@ConditionalOnExpression:	基于SpEL表达式的条件判断。
@ConditionalOnJava:	当JVM版本为指定的版本范围时触发实例化。
@ConditionalOnResource:	当类路径下有指定的资源时触发实例化。
@ConditionalOnJndi:	在JNDI存在的条件下触发实例化。
@ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者有多个但是指定了首选的Bean时触发实例化。

SpringBoot 扩展机制 ——Spring.factories文件 如何将外部项目加入Spring容器_第4张图片

▶ 如何使用IOC容器对象

1.@Autowired 2.ApplicationContext

@RunWith(SpringRunner.class)
@SpringBootTest(classes = WebDemoApplication.class)
public class JunitTest {
//    @Autowired
//    private TestClass testClass;

    @Test
    public void customYAMLTest(){
        TestClass bean = BeanFactoryUtil.getBean(TestClass.class);
        System.out.println(JSON.toJSONString(bean));
    }
}

BeanFactoryUtil

/**
 * Spring 上下文 获取
 *
 * @Author MostSnails
 * @Version 1.0
 */
public class BeanFactoryUtil {
    private static ApplicationContext context;

    public static void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (context == null){
            context = applicationContext;
        }
    }
    // 获取applicationContext
    private static ApplicationContext getApplicationContext() {
        return context;
    }

    // 通过name获取Bean
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);
    }

    // 通过class获取Bean
    public static  T getBean(Class clazz) {
        return getApplicationContext().getBean(clazz);
    }

    // 通过name,以及Clazz返回指定的Bean
    public static  T getBean(String name, Class clazz) {
        return getApplicationContext().getBean(name, clazz);
    }
}

SpringBoot 扩展机制 ——Spring.factories文件 如何将外部项目加入Spring容器_第5张图片

你可能感兴趣的:(SpringBoot,JAVA,spring,boot,spring,java)