基於SpringBoot註解實現策略模式
阿新 • • 發佈:2022-03-02
原始碼meethigher/springboot-strategy-mode
參考文章
還是來自於工作上的一點心得。之前我做的資料庫的通用呼叫儲存過程的程式碼,是使用抽象工廠來實現的,裡面有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;
}
}
}