讓Spring Boot項目啟動時可以根據(jù)自定義配置決定初始化哪些Bean

問題描述

目前我工作環(huán)境下,后端主要的框架是Spring Boot,目前面臨的問題也是在Spring Boot中出現(xiàn)的.

具體情況是這樣的,期望是搭建一個公用的框架,適用于多種業(yè)務場景的,集成好如Redis,日志管理,定時任務管理等一系列配置即用的框架,但是在集成好Activiti框架后我發(fā)現(xiàn)有的項目并不需要使用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,這個時候會出現(xiàn)以下問題:

  • 初始化這些我用不到的bean可能需要一些配置文件等資源,而這個框架因為這個項目沒有使用,所以沒有從而導致的啟動報錯[在我目前的場景下是沒有Activiti的流程圖文件]
  • 即便初始化這些JAVA Bean沒有問題,但是某些依賴可能會改變我數(shù)據(jù)庫的表結(jié)構(gòu)[在我這個場景下是會在我的數(shù)據(jù)庫中添加25個以ACT_開頭的表]
  • 當部署的服務器資源比較緊張的時候,這些多余的JAVA Bean會額外占用本來就不多的內(nèi)存資源

由于我自己對Activiti的方法還做了一些封裝,相當于提供了一個Service層的接口來使得代碼編寫更加簡單,這部分代碼我并不希望從腳手架中刪除掉,比較部分項目還是需要使用的,所以我現(xiàn)在需要實現(xiàn)的就是在Spring Boot項目啟動的時候,讓它根據(jù)我在application.yml文件中的配置來確定需要初始化哪些JAVA Bean.

實現(xiàn)思路

這里我有三個思路:
思路一:直接移除相關依賴
思路二:增加一個自定義的注解,當滿足我的配置的時候我再初始化我的Bean否則不初始化這些Bean
思路三:把我對Activiti的包裝部分集合成一個項目,然后提供一個類似于activiti-spring-boot-starter的start類型的包給到我的具體項目中去
思路一[不符合要求]
之前也提到了,由于我自己對Activiti的方法還做了一些封裝,如果移除了Activiti的Maven依賴,會直接導致我封裝的代碼報錯,所以這種方式并不能滿足我的要求,不在贅述
思路二[滿足要求]
這里我參照了簡書作者@數(shù)齊的名為SpringBoot基礎教程(十八)——自定義條件注解的博文,成功實現(xiàn)了根據(jù)我的配置加載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 {
 }
  • 注解的實現(xiàn)
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();
        //配置項內(nèi)容設置
        configuration
                //設置數(shù)據(jù)庫的類型
                .setDatabaseType("mysql")
                //使用springboot自帶的數(shù)據(jù)源
                .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之間的沖突問題.在當前的情況下,我已經(jīng)在項目啟動的時候完成了我自己類的去除,只要再去掉由于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關閉的類結(jié)束 
})

這時啟動我的項目,發(fā)現(xiàn)數(shù)據(jù)庫中并沒有生成ACT_開頭的表,也就意味著我已經(jīng)完全去除了activiti-spring-boot-starter-basic所帶來的JAVA Bean.

至此問題圓滿解決.

思路三[未試驗]

目前來說思路二是把和Activiti相關的初始化,封裝的方法單獨抽成一個JAR依賴,在需要它的時候引入這個依賴,這樣Spring Boot在啟動的時候是覺得不會裝配多余的JAVA Bean,之前面臨的問題也能得到有效的解決.因為時間問題,我沒有試驗這個思路,希望以后有機會填坑.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末索昂,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌挺尿,老刑警劉巖冤馏,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件焕妙,死亡現(xiàn)場離奇詭異纬霞,居然都是意外死亡冻辩,警方通過查閱死者的電腦和手機越败,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進店門触幼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人眉尸,你說我怎么就攤上這事域蜗。” “怎么了噪猾?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵霉祸,是天一觀的道長。 經(jīng)常有香客問我袱蜡,道長丝蹭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任坪蚁,我火速辦了婚禮奔穿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘敏晤。我一直安慰自己贱田,他們只是感情好,可當我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布嘴脾。 她就那樣靜靜地躺著男摧,像睡著了一般蔬墩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上耗拓,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天拇颅,我揣著相機與錄音,去河邊找鬼乔询。 笑死樟插,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的竿刁。 我是一名探鬼主播黄锤,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼们妥!你這毒婦竟也來了猜扮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤监婶,失蹤者是張志新(化名)和其女友劉穎旅赢,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體惑惶,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡煮盼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了带污。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片僵控。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖鱼冀,靈堂內(nèi)的尸體忽然破棺而出报破,到底是詐尸還是另有隱情,我是刑警寧澤千绪,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布充易,位于F島的核電站,受9級特大地震影響荸型,放射性物質(zhì)發(fā)生泄漏盹靴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一瑞妇、第九天 我趴在偏房一處隱蔽的房頂上張望稿静。 院中可真熱鬧,春花似錦辕狰、人聲如沸改备。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽绍妨。三九已至润脸,卻和暖如春柬脸,著一層夾襖步出監(jiān)牢的瞬間他去,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工倒堕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留灾测,地道東北人。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓垦巴,卻偏偏與公主長得像媳搪,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子骤宣,可洞房花燭夜當晚...
    茶點故事閱讀 42,786評論 2 345