問題描述
目前我工作環(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,之前面臨的問題也能得到有效的解決.因為時間問題,我沒有試驗這個思路,希望以后有機會填坑.