源码meethigher/springboot-strategy-mode
参考文章
-
springboot基于注解方式实现策略模式_aogula的博客-CSDN博客,主要抄袭自这篇文章
还是来自于工作上的一点心得。之前我做的数据库的通用调用存储过程的代码,是使用抽象工厂来实现的,里面有if..else..的操作。如果要频繁的新加数据库实现逻辑,就要不断的添加实现类和else if。这边就想用注解的方式,来去除if..else..
一、简单demo
案例:发送不同类型的消息
创建注解
@Target({ElementType.TYPE})//作用在类上
@Retention(RetentionPolicy.RUNTIME)//当前被描述的注解,会保留到class字节码文件中,并被jvm读取到。一般也只会用到这个
@Documented//注解被抽取到api文档中
@Inherited//注解被子类继承
public @interface MsgType {
MessageType value();
}
创建类型
public enum MessageType {
/**
* 微信·
*/
WECHAT_MSG,
/**
* 短信
*/
SMS_MSG
}
创建接口
public interface MessageHandler {
/**
* 发送消息
* @param msg
*/
String sendMessage(String msg);
}
创建SMS实现类
@Service
@MsgType(value = MessageType.SMS_MSG)
public class SmsMessageHandler implements MessageHandler {
@Override
public String sendMessage(String msg) {
String message = "短信消息:" + msg;
System.out.println(message);
return message;
}
}
创建WECHAT实现类
@Service
@MsgType(value = MessageType.WECHAT_MSG)
public class WechatMessageHandler implements MessageHandler {
@Override
public String sendMessage(String msg) {
String message = "微信消息:" + msg;
System.out.println(message);
return message;
}
}
创建配置类
- 通过注解拿到所有被标注的bean类
- 遍历所有bean,拿到bean的类型、字节码
- 将类型、字节码存入全局map
- 使用时,通过类型,将字节码取出,instance或者通过spring放入bean容器
@Component
public class MessageConfig implements ApplicationContextAware {
private static Map<MessageType, Class<MessageHandler>> messageTypeClassMap = new HashMap<>();
@Autowired
private ApplicationContext applicationContext;
/**
* 1. 通过注解拿到所有被标注的bean类
* 2. 遍历所有bean,拿到bean的类型、字节码
* 3. 将类型、字节码存入全局map
* 4. 使用时,通过类型,将字节码取出,instance或者通过spring放入bean容器
*
* @param applicationContext
* @throws BeansException
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//比较平易近人的写法
Map<String, Object> beans = applicationContext.getBeansWithAnnotation(MsgType.class);
Iterator<String> iterator = beans.keySet().iterator();
while (iterator.hasNext()) {
String beanName = iterator.next();
@SuppressWarnings("unchecked")
Class<MessageHandler> messageHandlerClass = (Class<MessageHandler>) beans.get(beanName).getClass();
MessageType messageType = messageHandlerClass.getAnnotation(MsgType.class).value();
messageTypeClassMap.put(messageType, messageHandlerClass);
}
//比较装逼的写法
// //获取所有带有指定注解的Bean对象
// applicationContext.getBeansWithAnnotation(MsgType.class)
// .entrySet()
// .iterator()
// .forEachRemaining(stringObjectEntry -> {
// Class<MessageHandler> messageHandlerClass = (Class<MessageHandler>) stringObjectEntry.getValue().getClass();
// MessageType messageType = messageHandlerClass.getAnnotation(MsgType.class).value();
// messageTypeClassMap.put(messageType, messageHandlerClass);
// });
}
/**
* 通过类型拿到实例化的对象
* @param messageType
* @return
*/
public MessageHandler getMessageHandler(MessageType messageType) {
Class<MessageHandler> messageHandlerClass = messageTypeClassMap.get(messageType);
if (ObjectUtils.isEmpty(messageHandlerClass)) {
throw new IllegalArgumentException("没有指定类型");
}
return applicationContext.getBean(messageHandlerClass);
}
}
二、实际案例
案例:根据频次来进行工作,频次有,一天一次,三天一次,七天一次,十天一次
创建枚举
public enum WorkFrequency {
/**
* 一天一次
*/
ONE_DAY_PER_TIMES("1天/次", "0", "oneDayPerTimes"),
/**
* 三天一次
*/
THREE_DAY_PER_TIMES("3天/次", "1", "threeDayPerTimes"),
/**
* 七天一次
*/
SEVEN_DAY_PER_TIMES("7天/次", "2", "sevenDayPerTimes"),
/**
* 十天一次
*/
TEN_DAY_PER_TIMES("10天/次", "3", "tenDayPerTimes"),
;
public final String name;
public final String value;
public final String uniqueCode;
WorkFrequency(String name, String value, String uniqueCode) {
this.name = name;
this.value = value;
this.uniqueCode = uniqueCode;
}
public static WorkFrequency getByUniqueCode(String uniqueCode) {
for (WorkFrequency frequency : WorkFrequency.values()) {
if (frequency.uniqueCode.equals(uniqueCode)) {
return frequency;
}
}
return null;
}
}
创建注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface FrequencyAnnotation {
WorkFrequency value();
}
创建接口
public interface WorkFrequencyHandler {
/**
* 今天是否应该执行
*
* @param lastExecuteTime
* @return
*/
boolean isTodayShouldExecute(Long lastExecuteTime);
}
创建实现类
public class WorkTimeUtils {
/**
* 两个时间相差天数
*
* @param startTime Date日期
* @param endTime Date日期
* @return
*/
public static int intervalDays(Date startTime, Date endTime) {
Calendar cal1 = Calendar.getInstance();
cal1.setTime(startTime);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(endTime);
int day1 = cal1.get(Calendar.DAY_OF_YEAR);
int day2 = cal2.get(Calendar.DAY_OF_YEAR);
int year1 = cal1.get(Calendar.YEAR);
int year2 = cal2.get(Calendar.YEAR);
/*同一年 */
if (year1 != year2) {
int timeDistance = 0;
for (int i = year1; i < year2; i++) {
if ((((i % 4) == 0) && ((i % 100) != 0)) || ((i % 400) == 0)) {
/* 闰年 */
timeDistance += 366;
} else {
/*不是闰年 */
timeDistance += 365;
}
}
return (timeDistance + (day2 - day1));
} else {
/*不同年 */
return (day2 - day1);
}
}
}
@Service
@FrequencyAnnotation(value = WorkFrequency.ONE_DAY_PER_TIMES)
public class OneDayOnceHandler implements WorkFrequencyHandler {
/**
* 间隔的天数
*/
private final Integer INTERVAL_DAY = 1;
@Override
public boolean isTodayShouldExecute(Long lastExecuteTime) {
long currentTimeMillis = System.currentTimeMillis();
int realIntervalDay = WorkTimeUtils.intervalDays(lastExecuteTime, currentTimeMillis);
if (realIntervalDay >= INTERVAL_DAY) {
return true;
} else {
return false;
}
}
}
@Service
@FrequencyAnnotation(value = WorkFrequency.THREE_DAY_PER_TIMES)
public class ThreeDayOnceHandler implements WorkFrequencyHandler {
/**
* 间隔的天数
*/
private final Integer INTERVAL_DAY = 3;
@Override
public boolean isTodayShouldExecute(Long lastExecuteTime) {
long currentTimeMillis = System.currentTimeMillis();
int realIntervalDay = WorkTimeUtils.intervalDays(lastExecuteTime, currentTimeMillis);
if (realIntervalDay >= INTERVAL_DAY) {
return true;
} else {
return false;
}
}
}
@Service
@FrequencyAnnotation(value = WorkFrequency.SEVEN_DAY_PER_TIMES)
public class SevenDayOnceHandler implements WorkFrequencyHandler {
/**
* 间隔的天数
*/
private final Integer INTERVAL_DAY = 7;
@Override
public boolean isTodayShouldExecute(Long lastExecuteTime) {
long currentTimeMillis = System.currentTimeMillis();
int realIntervalDay = WorkTimeUtils.intervalDays(lastExecuteTime, currentTimeMillis);
if (realIntervalDay >= INTERVAL_DAY) {
return true;
} else {
return false;
}
}
}
@Service
@FrequencyAnnotation(value = WorkFrequency.TEN_DAY_PER_TIMES)
public class TenDayOnceHandler implements WorkFrequencyHandler {
/**
* 间隔的天数
*/
private final Integer INTERVAL_DAY = 10;
@Override
public boolean isTodayShouldExecute(Long lastExecuteTime) {
long currentTimeMillis = System.currentTimeMillis();
int realIntervalDay = WorkTimeUtils.intervalDays(lastExecuteTime, currentTimeMillis);
if (realIntervalDay >= INTERVAL_DAY) {
return true;
} else {
return false;
}
}
}
添加配置类,通过配置类,直接获取Service
@Configuration
public class WorkFrequencyConfig implements ApplicationContextAware {
/**
* 存储对应关系
*/
private static Map<WorkFrequency, Class<WorkFrequencyHandler>> workFrequencyClassMap = new HashMap<>();
@Autowired
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
applicationContext.getBeansWithAnnotation(FrequencyAnnotation.class)
.entrySet()
.iterator()
.forEachRemaining(stringObjectEntry -> {
Class<WorkFrequencyHandler> aClass = (Class<WorkFrequencyHandler>) stringObjectEntry.getValue().getClass();
WorkFrequency messageType = aClass.getAnnotation(FrequencyAnnotation.class).value();
workFrequencyClassMap.put(messageType, aClass);
});
}
/**
* 通过类型拿到实例化的对象
*
* @param messageType
* @return
*/
public WorkFrequencyHandler getFrequencyHandler(WorkFrequency messageType) {
Class<WorkFrequencyHandler> workFrequencyHandlerClass = workFrequencyClassMap.get(messageType);
if (ObjectUtils.isEmpty(workFrequencyHandlerClass)) {
throw new IllegalArgumentException("没有指定类型");
}
return applicationContext.getBean(workFrequencyHandlerClass);
}
}
所有的配置好了,开始使用了。
@SpringBootTest
public class WorkTest {
@Autowired
private WorkFrequencyConfig workFrequencyConfig;
@Test
public void test() {
//模拟
People people = new People();
WorkFrequency workFrequency = WorkFrequency.getByUniqueCode(people.getFrequency());
WorkFrequencyHandler handler = workFrequencyConfig.getFrequencyHandler(workFrequency);
boolean todayShouldExecute = handler.isTodayShouldExecute(people.getLastWorkTime());
if(todayShouldExecute) {
System.out.println("今天应该工作");
}else {
System.out.println("今天不应该工作");
}
}
static class People {
private String frequency;
private Long lastWorkTime;
public People() {
//模拟
this.frequency = "oneDayPerTimes";
this.lastWorkTime = System.currentTimeMillis();
}
public String getFrequency() {
return frequency;
}
public void setFrequency(String frequency) {
this.frequency = frequency;
}
public Long getLastWorkTime() {
return lastWorkTime;
}
public void setLastWorkTime(Long lastWorkTime) {
this.lastWorkTime = lastWorkTime;
}
}
}