# annotation-strategy **Repository Path**: xiehongwei666/annotation-strategy ## Basic Information - **Project Name**: annotation-strategy - **Description**: SpringBoot 使用自定义注解实现策略模式【订单场景模拟】 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 2 - **Created**: 2021-10-09 - **Last Updated**: 2024-12-30 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 一、前言 整体思路:通过在策略类上使用自定义注解,定义的orderType不同来区分各种订单,再根据不同的orderType将策略类存储,使用时再根据orderType获取策略类做不同的处理。 代码结构:(案例以京东、淘宝、苏宁订单类型为例)
![代码结构](%E4%BB%A3%E7%A0%81%E7%BB%93%E6%9E%84.png) # 二、代码 ## 1、自定义策略注解 ### 注解 ```java import com.hong.strategy.enums.OrderTypeEnum; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 自定义策略注解 * * @author xiehongwei * @date 2021/10/08 */ @Target({ElementType.TYPE}) @Retention(value = RetentionPolicy.RUNTIME) public @interface OrderTypeAnnotation { /** * 策略订单类型 */ OrderTypeEnum orderType(); } ``` ### 枚举 ```java /** * 订单类型-枚举 * * @author xiehongwei * @date 2021/10/08 */ public enum OrderTypeEnum { TB(1, "淘宝订单"), JD(2, "京东订单"), SN(3, "苏宁订单"); private Integer orderType; private String desc; OrderTypeEnum(int orderType, String desc) { this.orderType = orderType; this.desc = desc; } public static OrderTypeEnum getEnum(Integer orderType) { OrderTypeEnum[] typeArray = OrderTypeEnum.values(); for (OrderTypeEnum typeEnum : typeArray) { if (typeEnum.getOrderType().equals(orderType)) { return typeEnum; } } return null; } //此处忽略get和set方法 } ``` ## 2、策略接口和实现 ### 说明 > OrderStrategy-接口
>         getUserInfo(获取用户信息)
>         getGoodsInfo(获取商品信息)
>         getDiscount(获取优惠金额)
> > AbstractOrderStrategy-抽象类
>         实现OrderStrategy接口所有方法
> > JdOrderStrategy-京东订单策略类
>         继承AbstractOrderStrategy抽象类
>         重写getGoodsInfo、getDiscount
> > SnOrderStrategy-苏宁订单策略类
>         继承AbstractOrderStrategy抽象类
>         重写getGoodsInfo、getDiscount
> > TbOrderStrategy-淘宝订单策略类
>         继承AbstractOrderStrategy抽象类
>         重写getGoodsInfo
### 订单策略-接口 ```java /** * 订单策略-接口 * * @author xiehongwei * @date 2021/10/08 */ public interface OrderStrategy { /** * 获取用户信息 */ String getUserInfo(String buyer); /** * 获取商品信息 */ String getGoodsInfo(String goodsName); /** * 获取优惠金额 */ Double getDiscount(); } ``` ### 订单策略-抽象类  存放一些通用的基础方法。若不同的实现类有不同的需求,可在实现类中重写该方法,来实现自定义业务逻辑 ```java import com.hong.strategy.strategys.service.OrderStrategy; /** * 订单策略-抽象类 * 存放一些通用的基础方法。 * 若不同的实现类有不同的需求,可在实现类中重写该方法,来实现自定义业务逻辑 * * @author xiehongwei * @date 2021/10/09 */ public abstract class AbstractOrderStrategy implements OrderStrategy { /** * 获取用户信息(默认实现) */ @Override public String getUserInfo(String buyer) { return buyer; } /** * 获取商品信息(默认实现) */ @Override public String getGoodsInfo(String goodsName) { return goodsName; } /** * 获取优惠金额(默认实现) */ @Override public Double getDiscount() { return 0.0; } } ``` ### 京东订单-策略类 ```java import com.hong.strategy.enums.OrderTypeEnum; import com.hong.strategy.strategys.annotation.OrderTypeAnnotation; import org.springframework.stereotype.Component; /** * 京东订单-策略类 * * @author xiehongwei * @date 2021/10/08 */ @Component @OrderTypeAnnotation(orderType = OrderTypeEnum.JD) public class JdOrderStrategy extends AbstractOrderStrategy { /** * 获取商品信息 */ @Override public String getGoodsInfo(String goodsName) { return "【京东】" + goodsName; } /** * 获取优惠金额 */ @Override public Double getDiscount() { return 50.0; } } ``` ### 苏宁订单-策略类 ```java import com.hong.strategy.enums.OrderTypeEnum; import com.hong.strategy.strategys.annotation.OrderTypeAnnotation; import org.springframework.stereotype.Component; /** * 苏宁订单-策略类 * * @author xiehongwei * @date 2021/10/08 */ @Component @OrderTypeAnnotation(orderType = OrderTypeEnum.SN) //使用注解标明策略类型 public class SnOrderStrategy extends AbstractOrderStrategy { /** * 获取商品信息 */ @Override public String getGoodsInfo(String goodsName) { return "【苏宁】" + goodsName; } /** * 获取优惠金额 */ @Override public Double getDiscount() { return 100.0; } } ``` ### 淘宝订单-策略类 ```java import com.hong.strategy.enums.OrderTypeEnum; import com.hong.strategy.strategys.annotation.OrderTypeAnnotation; import org.springframework.stereotype.Component; /** * 淘宝订单-策略类 * * @author xiehongwei * @date 2021/10/08 */ @Component @OrderTypeAnnotation(orderType = OrderTypeEnum.TB) public class TbOrderStrategy extends AbstractOrderStrategy { /** * 查询商品信息 */ @Override public String getGoodsInfo(String goodsName) { return "【淘宝】" + goodsName; } } ``` ## 3、核心功能实现 ```java import com.hong.strategy.enums.BizResultCode;` import com.hong.strategy.enums.OrderTypeEnum; import com.hong.strategy.exception.BizException; import com.hong.strategy.strategys.annotation.OrderTypeAnnotation; import com.hong.strategy.strategys.service.OrderStrategy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; /** * 根据订单类型返回对应的处理策略 * * @author xiehongwei * @date 2021/10/08 */ @Component public class HandlerOrderContext implements ApplicationContextAware { private static final Logger logger = LoggerFactory.getLogger(HandlerOrderContext.class); /** * 锁, 防止重复创建同一对象 */ private static final Object lock = new Object(); /** * 创建订单服务策略class集合 =<订单类型, 创建订单服务策略class> *

* 注:此集合只存放OrderStrategy的子类class,对应的实例交由spring容器来管理 */ private static Map> orderStrategyBeanMap = new HashMap<>(); @Autowired private static ApplicationContext applicationContext; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { HandlerOrderContext.applicationContext = applicationContext; } public static ApplicationContext getApplicationContext() { return applicationContext; } /** * 获取创建订单策略实例 * * @param orderType 订单类型 */ public static OrderStrategy getInstance(Integer orderType) { if (null == orderType) { throw new BizException(BizResultCode.ERR_PARAM.getCode(), "订单类型不能为空"); } OrderTypeEnum orderTypeEnum = OrderTypeEnum.getEnum(orderType); if (null == orderTypeEnum) { throw new BizException(BizResultCode.ERR_PARAM.getCode(), "暂时不支持该订单类型orderType=" + orderType); } // 当集合为空时,则初始化 if (orderStrategyBeanMap.size() == 0) { initStrategy(); } Class clazz = orderStrategyBeanMap.get(orderTypeEnum); if (null == clazz) { throw new BizException(BizResultCode.ERR_PARAM.getCode(), "未找到订单类型(" + orderTypeEnum + ")的创建订单策略实现类"); } // 从spring容器中获取bean return applicationContext.getBean(clazz); } /** * 初始化 */ private static void initStrategy() { synchronized (lock) { // 获取接口下所有实例bean Map strategyMap = applicationContext.getBeansOfType(OrderStrategy.class); if (null == strategyMap || strategyMap.size() == 0) { throw new BizException(BizResultCode.ERR_SYSTEM.getCode(), "代码配置错误:未获取到OrderStrategy的实现类,请检查代码中是否有将实现类bean注册到spring容器"); } // 加载所有策略类对应的配置 OrderTypeAnnotation annotation; for (Map.Entry strategy : strategyMap.entrySet()) { Class strategyClazz = strategy.getValue().getClass(); // 因为策略bean可能是经过动态代理生成的bean实例(可能是多重动态代理后的代理对象), // 故而bean实例的class可能已经不是原来的class了,所以beanClass.getAnnotation(...)获取不到对应的注解元信息 annotation = (OrderTypeAnnotation) strategyClazz.getAnnotation(OrderTypeAnnotation.class); if (null == annotation) { // 当从bean实例的class上获取不到注解元信息时,通过AnnotationUtils工具类递归来获取 annotation = AnnotationUtils.findAnnotation(strategyClazz, OrderTypeAnnotation.class); if (null == annotation) { logger.warn("代码配置错误:创建订单策略实现类{}未配置OrderTypeAnnotation注解", strategyClazz.getName()); continue; } } // 支持多个事件类型 OrderTypeEnum typeEnum = annotation.orderType(); //String key = getKey(typeEnum.getOrderType()); if (orderStrategyBeanMap.containsKey(typeEnum)) { logger.error("代码配置错误:一个订单类型({})只能对应一个创建订单策略实现{}", typeEnum, strategyClazz.getName()); throw new BizException(BizResultCode.ERR_SYSTEM.getCode(), "代码配置错误:一个订单类型(" + typeEnum + ")只能对应一个创建订单策略实现bean"); } orderStrategyBeanMap.put(typeEnum, strategyClazz); } if (orderStrategyBeanMap.size() == 0) { logger.warn("初始化创建订单策略集合失败"); } } } } ``` ## 4、实体类 ```java /** * 订单-实体类 * * @author xiehongwei * @date 2021/10/08 */ public class Order { /** * 购买人 */ private String buyer; /** * 商品名称 */ private String goodsName; /** * 金额 */ private Double price; /** * 订单类型 */ private Integer orderType; //此处忽略get和set } ``` ## 5、业务层 ### 接口 ```java import com.hong.strategy.entity.Order; /** * 订单-业务层 * * @author xiehongwei * @date 2021/10/08 */ public interface OrderService { String handleOrder(Order order); } ``` ### 实现类 ```java import com.hong.strategy.entity.Order; import com.hong.strategy.service.OrderService; import com.hong.strategy.strategys.config.HandlerOrderContext; import com.hong.strategy.strategys.service.OrderStrategy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** * 订单-实现类 * * @author xiehongwei * @date 2021/10/08 */ @Component public class OrderServiceImpl implements OrderService { private static final Logger logger = LoggerFactory.getLogger(HandlerOrderContext.class); @Override public String handleOrder(Order order) { try { // 根据订单类型获取对应的创建订单策略 OrderStrategy orderStrategy = HandlerOrderContext.getInstance(order.getOrderType()); String userInfo = orderStrategy.getUserInfo(order.getBuyer()); String goodsInfo = orderStrategy.getGoodsInfo(order.getGoodsName()); Double discount = orderStrategy.getDiscount(); String msg = "\n购买人信息:" + userInfo + "\n商品信息:" + goodsInfo + "\n优惠金额:" + discount + "\n原价:" + order.getPrice() + "\n优惠后金额:" + (order.getPrice() - discount); logger.info(msg); return msg; } catch (Exception e) { return e.getMessage(); } } } ``` ## 6、控制层 ```java import com.hong.strategy.entity.Order; import com.hong.strategy.service.OrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * 订单-控制层 * * @author xiehongwei * @date 2021/10/08 */ @RestController @RequestMapping("/order") public class OrderController { @Autowired private OrderService orderService; @GetMapping("/handler") public String handleOrder(Integer orderType) { Order order = new Order(); order.setBuyer("小明"); order.setGoodsName("华为手机"); order.setPrice(3999.9); order.setOrderType(orderType); return orderService.handleOrder(order); } } ``` # 三、测试 ## 淘宝订单类型-测试结果
重写了【获取商品信息】接口,在商品名称前加上了【淘宝】字样
未重写【获取优惠金额】接口
![淘宝订单类型-测试结果](%E6%B7%98%E5%AE%9D%E8%AE%A2%E5%8D%95%E7%B1%BB%E5%9E%8B-%E6%B5%8B%E8%AF%95%E7%BB%93%E6%9E%9C.png) ## 京东订单类型-测试结果
重写了【获取商品信息】接口,在商品名称前加上了【京东】字样
重写了【获取优惠金额】接口,优惠金额50元
![京东订单类型-测试结果](%E4%BA%AC%E4%B8%9C%E8%AE%A2%E5%8D%95%E7%B1%BB%E5%9E%8B-%E6%B5%8B%E8%AF%95%E7%BB%93%E6%9E%9C.png) ## 苏宁订单类型-测试结果
重写了【获取商品信息】接口,在商品名称前加上了【苏宁】字样
重写了【获取优惠金额】接口,优惠金额100元
![苏宁订单类型-测试结果](%E8%8B%8F%E5%AE%81%E8%AE%A2%E5%8D%95%E7%B1%BB%E5%9E%8B-%E6%B5%8B%E8%AF%95%E7%BB%93%E6%9E%9C.png) # 四、源码地址(码云gitee): [annotation-strategy: SpringBoot 使用自定义注解实现策略模式【订单场景模拟】](https://gitee.com/custom116/annotation-strategy) ​