基于SpringBoot注解实现策略模式
Posted 言成言成啊
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于SpringBoot注解实现策略模式相关的知识,希望对你有一定的参考价值。
源码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;
以上是关于基于SpringBoot注解实现策略模式的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot自定义注解+异步+观察者模式实现业务日志保存
SpringBoot2.0 基础案例(13):基于Cache注解模式,管理Redis缓存
SpringBoot EnableAsync无效 Async注解不异步