美文网首页
让Spring Boot项目启动时可以根据自定义配置决定初始化哪

让Spring Boot项目启动时可以根据自定义配置决定初始化哪

作者: 紫川弘 | 来源:发表于2019-01-30 14:32 被阅读0次

    问题描述

    目前我工作环境下,后端主要的框架是Spring Boot,目前面临的问题也是在Spring Boot中出现的.

    具体情况是这样的,期望是搭建一个公用的框架,适用于多种业务场景的,集成好如Redis,日志管理,定时任务管理等一系列配置即用的框架,但是在集成好Activiti框架后我发现有的项目并不需要使用Activiti框架,但是由于我使用的Maven依赖如下:

    <dependency>   
      <groupId>org.activiti</groupId> 
      <artifactId>activiti-spring-boot-starter-basic</artifactId> 
      <version>${activiti.version}</version> 
    </dependency> 
    <dependency> 
      <groupId>org.activiti</groupId> 
      <artifactId>activiti-spring-boot-starter-actuator</artifactId> 
      <version>${activiti.version}</version> 
    </dependency>
    

    可以看到是使用了starter系列的依赖,所以Spring Boot会在启动时默认初始化Activiti相关的JAVA Bean,这个时候会出现以下问题:

    • 初始化这些我用不到的bean可能需要一些配置文件等资源,而这个框架因为这个项目没有使用,所以没有从而导致的启动报错[在我目前的场景下是没有Activiti的流程图文件]
    • 即便初始化这些JAVA Bean没有问题,但是某些依赖可能会改变我数据库的表结构[在我这个场景下是会在我的数据库中添加25个以ACT_开头的表]
    • 当部署的服务器资源比较紧张的时候,这些多余的JAVA Bean会额外占用本来就不多的内存资源

    由于我自己对Activiti的方法还做了一些封装,相当于提供了一个Service层的接口来使得代码编写更加简单,这部分代码我并不希望从脚手架中删除掉,比较部分项目还是需要使用的,所以我现在需要实现的就是在Spring Boot项目启动的时候,让它根据我在application.yml文件中的配置来确定需要初始化哪些JAVA Bean.

    实现思路

    这里我有三个思路:
    思路一:直接移除相关依赖
    思路二:增加一个自定义的注解,当满足我的配置的时候我再初始化我的Bean否则不初始化这些Bean
    思路三:把我对Activiti的包装部分集合成一个项目,然后提供一个类似于activiti-spring-boot-starter的start类型的包给到我的具体项目中去
    思路一[不符合要求]
    之前也提到了,由于我自己对Activiti的方法还做了一些封装,如果移除了Activiti的Maven依赖,会直接导致我封装的代码报错,所以这种方式并不能满足我的要求,不在赘述
    思路二[满足要求]
    这里我参照了简书作者@数齐的名为SpringBoot基础教程(十八)——自定义条件注解的博文,成功实现了根据我的配置加载Bean的功能,核心代码如下:

    • 注解
    import com.hykj.activiti.annotation.impl.ActivitiConditionImpl;
    import org.springframework.context.annotation.Conditional; 
    import java.lang.annotation.Documented; 
    import java.lang.annotation.ElementType; 
    import java.lang.annotation.Retention; 
    import java.lang.annotation.RetentionPolicy; 
    import java.lang.annotation.Target; 
    
    @Retention(RetentionPolicy.RUNTIME) 
    @Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) 
    @Documented 
    @Conditional(ActivitiConditionImpl.class) 
    public @interface ActivitiCondition {
     }
    
    • 注解的实现
    import com.google.common.base.Strings;
    import org.springframework.context.annotation.Condition;
    import org.springframework.context.annotation.ConditionContext;
    import org.springframework.core.type.AnnotatedTypeMetadata;
    
    /**
     * 是否需要activiti的注解<br/>
     * 如果需要activiti的话,那么在application加入sys.need-activiti=true <br/>
     * 其他情况不再初始化activiti的相关bean
     *
     * @author weizj
     */
    public class ActivitiConditionImpl implements Condition {
    
        /** 启动的配置值 */
        private static String ENABLE = "true";
        /** 配置的属性名 */
        private static String CONFIG_PROPERTY_NAME = "sys.need-activiti";
    
    
        @Override
        public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
    
            String propertyValue = conditionContext.getEnvironment().getProperty(CONFIG_PROPERTY_NAME);
    
            return !Strings.isNullOrEmpty(propertyValue) && propertyValue.equalsIgnoreCase(ENABLE);
    
        }
    }
    
    • 应用注解
    import com.hykj.activiti.annotation.ActivitiCondition;
    import org.activiti.engine.ProcessEngineConfiguration;
    import org.activiti.engine.impl.history.HistoryLevel;
    import org.activiti.spring.SpringProcessEngineConfiguration;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.jdbc.datasource.DataSourceTransactionManager;
    import org.springframework.transaction.PlatformTransactionManager;
    
    import javax.sql.DataSource;
    
    /**
     * Activiti流程引擎的配置
     */
    @Configuration
    @ActivitiCondition
    public class ActivitiConfig {
    
        @Autowired
        public ActivitiConfig(DataSource dataSource) {
            this.dataSource = dataSource;
        }
    
        private DataSource dataSource;
    
        @Bean
        public PlatformTransactionManager transactionManager() {
            return new DataSourceTransactionManager(dataSource);
        }
    
        @Bean
        public SpringProcessEngineConfiguration springProcessEngineConfiguration() {
            System.out.println("=======================");
            SpringProcessEngineConfiguration configuration = new SpringProcessEngineConfiguration();
            //配置项内容设置
            configuration
                    //设置数据库的类型
                    .setDatabaseType("mysql")
                    //使用springboot自带的数据源
                    .setDataSource(dataSource)
                    //设置字段更新类型
                    .setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE)
                    //
                    .setJobExecutorActivate(true)
                    //设置历史记录级别
                    .setHistoryLevel(HistoryLevel.FULL)
                    //设置标签字体
                    .setLabelFontName("宋体")
                    //设置注解字体
                    .setAnnotationFontName("宋体")
                    //设置图形字体
                    .setActivityFontName("宋体")
            ;
    
            configuration.setTransactionManager(transactionManager());
            return configuration;
        }
    }
    
    • 配置文件配置
    sys: need-activiti: 11
    

    到这里为止,如果配置文件中sys.need-activiti的值为true的时候Spring Boot启动的时候才会加载我配置的ActivitiConfig类中的Bean,但是这并不能让Spring Boot在启动的时候不初始化Activiti相关的如:RuntimeService/IdentityService/TaskService/RepositoryService/HistoryService等由activiti-spring-boot-starter-basic依赖自动装配的Bean.

    正当我以为这条路走不通的时候我看到了@SpringBootApplication注解中包含exclude属性,我之前用它排除了org.activiti.spring.boot.SecurityAutoConfiguration.class类来避免Activiti的安全认证和Spring Secrity以及Apache Shrio之间的冲突问题.在当前的情况下,我已经在项目启动的时候完成了我自己类的去除,只要再去掉由于activiti-spring-boot-starter-basic包存在所初始化的类大概就可以了,于是我的@SpringBootApplication

    @SpringBootApplication(exclude = { SecurityAutoConfiguration.class,org.activiti.spring.boot.SecurityAutoConfiguration.class})
    

    变成了:

    @SpringBootApplication(exclude = { 
      SecurityAutoConfiguration.class, //不论是否使用activiti都要关闭这个类
      org.activiti.spring.boot.SecurityAutoConfiguration.class, //不使用activiti关闭的类开始 
      org.activiti.spring.boot.EndpointAutoConfiguration.class, 
      org.activiti.spring.boot.JpaProcessEngineAutoConfiguration.class, 
      org.activiti.spring.boot.DataSourceProcessEngineAutoConfiguration.class, 
      org.activiti.spring.boot.RestApiAutoConfiguration.class //不使用activiti关闭的类结束 
    })
    

    这时启动我的项目,发现数据库中并没有生成ACT_开头的表,也就意味着我已经完全去除了activiti-spring-boot-starter-basic所带来的JAVA Bean.

    至此问题圆满解决.

    思路三[未试验]

    目前来说思路二是把和Activiti相关的初始化,封装的方法单独抽成一个JAR依赖,在需要它的时候引入这个依赖,这样Spring Boot在启动的时候是觉得不会装配多余的JAVA Bean,之前面临的问题也能得到有效的解决.因为时间问题,我没有试验这个思路,希望以后有机会填坑.

    相关文章

      网友评论

          本文标题:让Spring Boot项目启动时可以根据自定义配置决定初始化哪

          本文链接:https://www.haomeiwen.com/subject/ahuhrqtx.html