问题:
一个项目中会包含多个定时任务(spring Scheduled),由于每个任务需要的资源等不同,需要将他们分开部署,但又不想分开项目编写,所以有了这个问题
【解决方法】:
(第三种是这里的解决方法)
1.注释掉不需要的定时任务的配置然后编译部署
问题:但这样线上部署的代码和master会有区别,分开的定时任务过多时每次都分开编译很麻烦
//@Scheduled(cron = "${user.cancel.job.cron}")
public void run(){
System.out.println("UserCancelJob...");
}
2.配置不需要的定时任务cron为多年后
问题:大致可以实现,但从代码配置上讲不完美,万一程序真跑到那一年(哈哈),从代码上来讲不是完美的方案。
@Scheduled(cron = "${user.cancel.job.cron}")
public void run(){...}
配置文件
user.cancel.job.cron=0 07 10 15 1 ? 2099
3.根据配置文件配置当前项目中不需要的配置,使spring不加载某些bean
不仅可用于当前这种定时任务,对于其他业务场景都可以,在项目启动时不加载某些bean,动态配置项目。
spring根据配置设置不加载的bean
实现过程
1.配置文件添加配置exclude.bean.classList
exclude.bean.classList=com.pack.a.class,com.pack.b.class
2.springboot启动类配置包扫描时配置不加载的bean过滤器
@ComponentScan(
basePackages = "com.mjw",
excludeFilters = {
//根据注解过滤不加载的Bean
//@ComponentScan.Filter(type=FilterType.ANNOTATION, value= {ExcludeBean.class}),
//根据自定义过滤器过滤不加载的Bean
@ComponentScan.Filter(type=FilterType.CUSTOM, value= {ExcludeBeanFilter.class})
}
)
3.过滤器中根据配置文件判断是否包含配置
由于需要spring在加载bean前使用配置,不能使用spring注入方式加载配置文件,需要自己手动读取配置文件(工具类PropertiesUtils放在最后)
public class ExcludeBeanConfig {
private static List<String> classList;
static {
classList = new ArrayList<>();
Properties properties = null;
try{
properties = PropertiesUtils.loadProperties("classpath:application.properties");
}catch (Exception e){
throw new RuntimeException("APPLICATION CONF NOT EXIST...");
}
Object pro = properties.get(GlobalConstants.SPRING_EXCLUDE_BEAN_CONFIG);//就是exclude.bean.classList
if(null != pro){
classList = Arrays.asList(String.valueOf(pro).split(","));
}
}
public static boolean contanisClass(String clazzName){
if(StringUtils.isBlank(clazzName)){
return false;
}
if(CollectionUtils.isEmpty(classList)){
return false;
}
for(String clazz : classList){
if(clazzName.equals(clazz)){
return true;
}
}
return false;
}
}
不加载Bean过滤器
package cn.com.gc.core.spring;
import cn.com.gc.core.config.ExcludeBeanConfig;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import java.io.IOException;
/**
* @Description 不加载Bean过滤器
* @Author MinJunWen
* @Data 2019/7/4 11:01
* @Version 1.0.0
**/
public class ExcludeBeanFilter implements TypeFilter {
/**
* @Title
* @Description 是否符合此过滤,返回true即符合。
* @param
* @return boolean
* @throw
* @author MinJunWen
* @date 2019/7/4 11:02
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
if(ExcludeBeanConfig.contanisClass(metadataReader.getClassMetadata().getClassName())){
return true;
}
return false;
}
}
这样在项目启动后,会发现配置的bean就不会加载,相应的定时任务(或其他)都可以不执行了。
小结
此方法不仅可用于配置定时任务,其他相同需要根据配置动态加载或移除某些bean的场景都可以用到,spring配置不加载的bean过滤器时,除了自定义也提供了根据注解,根据正则,且面等多种方式。
这里留一下上面用到的工具类吧
public class PropertiesUtils {
private static final String DEFAULT_ENCODING = "UTF-8";
private static Log logger = LogFactory.getLog(PropertiesUtils.class);
private static PropertiesPersister propertiesPersister = new DefaultPropertiesPersister();
private static ResourceLoader resourceLoader = new DefaultResourceLoader();
/**
* 载入多个properties文件, 相同的属性在最后载入的文件中的值将会覆盖之前的载入. 文件路径使用Spring Resource格式,
* 文件编码使用UTF-8.
*
* @see org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
*/
public static Properties loadProperties(String... resourcesPaths)
throws IOException {
Properties props = new Properties();
for (String location : resourcesPaths) {
logger.debug("Loading properties file from:" + location);
InputStream is = null;
try {
Resource resource = resourceLoader.getResource(location);
is = resource.getInputStream();
propertiesPersister.load(props, new InputStreamReader(is,
DEFAULT_ENCODING));
} catch (IOException ex) {
logger.info("Could not load properties from classpath:"
+ location + ": " + ex.getMessage());
} finally {
if (is != null) {
is.close();
}
}
}
return props;
}
}