利用springboot初始化机制三种实现策略模式的应用

面试时总被问,spring中使用了哪些设计模式,你在实际开发中又使用哪些设计模式。给他手指一个方向跟他说,这就是一个模式:go out!。
这就是一种模式:策略模式,一个接口的多个实现方式(算法)。本文梳理了使用springboot实现的三种实现策略模式的应用
我们知道,springboot应用初始化的过程是通过事件机制进行的。主要是通过 EventPublishingRunListener 在不同的初始化阶段发送不同的 SpringApplicationEvent (不同的子)事件,触发相应逻辑(这里的逻辑指class的加载)的加载和初始化。
当 ApplicationPreparedEvent 事件发送后,对于应用来讲,说明整个初始化过程已完成,也意味着所有的类已放入spring ioc 中。
这时我们就可以结合自己的业务逻辑实现策略模式的应用,我们通过以下三种方式实现策略的应用
方式一:使用ApplicationListener 和 ContextRefreshedEvent
核心使用的是 ApplicationContext.getBeanNamesForAnnotation(Class annotationType)方法,基于注解类,获取标有指定注解类的所有实例
我们的业务逻辑是这样的:应用Api接收规则参数(authType),Api 根据authType 值的不同,使用不同的auth service,执行相应的规则业务逻辑。
public interface UserValidator {

String check(D data, R rule);œ

}
@Service
@Validator(authType = AuthType.B_USER)
public class BUserValidator implements UserValidator {

@Override
public String check(String data, String rule) {
    System.out.println("客官,这里B端用户逻辑");
    return "";
}

}
@Service
@Validator(authType = AuthType.C_USER)
public class CUserValidator implements UserValidator {

@Override
public String check(String data, String rule) {
    System.out.println("客官,这里C端用户逻辑");
    return "";
}

}
public enum AuthType {

B_USER(1, "b端用户"),
C_USER(2, "c端用户");

public final int type;

public final String code;

AuthType(int type, String code) {
    this.type = type;
    this.code = code;
}

}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
@Inherited
public @interface Validator {

AuthType authType();

}
@Component
public class AuthContainer implements ApplicationListener {

private ConcurrentHashMap validatorMap = new ConcurrentHashMap<>();

@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
    String[] names = context.getBeanNamesForAnnotation(Validator.class);
    if (names.length > 0) {
        for (String name : names) {
            System.out.println("UserValidator:" + name);
            UserValidator userValidator = context.getBean(name, UserValidator.class);
            Validator validator = userValidator.getClass().getAnnotation(Validator.class);
            validatorMap.put(validator.authType().type, userValidator);
        }
    }
}

public ConcurrentHashMap getValidatorMap() {
    return validatorMap;
}

}
复制代码
Api 接口定义如下,根据不同的authType 值,执行不同的auth service
@RequestMapping("/client_auth")
@RestController
public class Client3 {

@Autowired
private AuthContainer authContainer;

@RequestMapping("getAuth")
public String getRule(@RequestParam("authType") Integer authType) {
    // if authType=1,B_USER; if authType=2,C_USER;
    ConcurrentHashMap map = authContainer.getValidatorMap();
    UserValidator userValidator = map.get(authType);
    String res = userValidator.check("hi", "看看什么规则");
    return res;
}

}
复制代码
方式二:使用ApplicationContextAware 和 @PostConstruct
我们的业务逻辑是这样的:应用Api接收规则参数(ruleType),Api 根据ruleType 值的不同,使用不同的rule service,执行相应的规则业务逻辑。
核心使用的是 ApplicationContext.getBeanNamesForAnnotation(Class annotationType)方法,基于注解类,获取标有指定注解类的所有实例
代码结构:

利用springboot初始化机制三种实现策略模式的应用_第1张图片

核心代码如下:
public abstract class RuleValidator {

public abstract String check(D data, R rule);

}
@RuleMapping(ruleCodeEnum = RuleCodeEnum.COUNT)
@Service
public class CountRuleValidator extends RuleValidator {

@Override
public String check(String data, String rule) {
    System.out.println("客官,这里是数量规则区域");
    return "";
}

}
@RuleMapping(ruleCodeEnum = RuleCodeEnum.PRICE)
@Service
public class PriceRuleValidator extends RuleValidator {

@Override
public String check(String data, String rule) {
    System.out.println("客官,这里是价格规则区域");
    return "";
}

}
public enum RuleCodeEnum {

/** 价格规则 */
PRICE(1, "price"),
/** 数量规则 */
COUNT(2, "count");

public final int type;
public final String code;

RuleCodeEnum(int type, String code) {
    this.type = type;
    this.code = code;
}

}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
@Inherited
public @interface RuleMapping {

String ruleCode() default "";
String ruleDesc() default "";
RuleCodeEnum ruleCodeEnum();

}

@Component
public class RuleValidatorInit implements ApplicationContextAware {

private static ApplicationContext context;
private Map validatorMap = new HashMap<>();

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.context = applicationContext;
}
public Map getValidatorMap() {
    return validatorMap;
}
@PostConstruct
public void afterPropertiesSet() {
    String[] names = context.getBeanNamesForAnnotation(RuleMapping.class);
    if (names.length > 0) {
        for (String name : names) {
            RuleValidator ruleValidator = context.getBean(name, RuleValidator.class);
            RuleMapping ruleMapping = ruleValidator.getClass().getAnnotation(RuleMapping.class);
            validatorMap.put(ruleMapping.ruleCodeEnum().type, ruleValidator);
        }
    }
}

}
复制代码
Api 接口定义如下,根据不同的ruleType 值,执行不同的rule service
@RequestMapping("/client")
@RestController
public class Client {

@Autowired
private RuleValidatorInit ruleValidatorInit;

@RequestMapping("getRule")
public String getRule(@RequestParam("ruleType") Integer ruleType) {
    Map map = ruleValidatorInit.getValidatorMap();
    System.out.println(map);
    RuleValidator ruleValidator = map.get(ruleType);
    String res = ruleValidator.check("hi", "看看什么规则");
    return res;
}

}
复制代码
方式三:使用ApplicationContextAware
对比方式一,这里不需要定义指定注解了
核心使用的是 ApplicationContext.getBeansOfType(classType)方法,获取接口 classType 的所有子类实例
代码结构:

利用springboot初始化机制三种实现策略模式的应用_第2张图片

核心代码如下:
public interface RoleValidator {

String check(D data, R rule);
RoleCodeEnum source();

}
@Service
public class BRoleValidator implements RoleValidator {

@Override
public String check(String data, String rule) {
    System.out.println("客官,这里B端用户逻辑");
    return "";
}
@Override
public RoleCodeEnum source() {
    return RoleCodeEnum.B_USER;
}

}
@Service
public class CRoleValidator implements RoleValidator {

@Override
public String check(String data, String rule) {
    System.out.println("客官,这里C端用户逻辑");
    return "";
}
@Override
public RoleCodeEnum source() {
    return RoleCodeEnum.C_USER;
}

}
public enum RoleCodeEnum {

B_USER(1, "b端用户"),
C_USER(2, "c端用户");

public final int type;
public final String code;

RoleCodeEnum(int type, String code) {
    this.type = type;
    this.code = code;
}

}
@Component
public class RoleValidatorInit implements ApplicationContextAware {

private static Map builderMap = new HashMap<>();

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    for (RoleValidator roleValidator : applicationContext.getBeansOfType(RoleValidator.class).values()) {
        builderMap.put(roleValidator.source(), roleValidator);
    }
}
public static RoleValidator getRoleValidator(RoleCodeEnum role) {
    return builderMap.get(role);
}

}
复制代码
Api 接口定义如下,根据不同的roleType 值,执行不同的role service
@RequestMapping("/client_role")
@RestController
public class Client2 {

@Autowired
private RoleValidatorInit roleValidatorInit;

@RequestMapping("getRole")
public String getRule(@RequestParam("roleType") Integer roleType) {
    // if roleType=1,B_USER; if roleType=2,C_USER;
    RoleValidator roleValidator = roleValidatorInit.getRoleValidator(RoleCodeEnum.B_USER);
    String res = roleValidator.check("hi", "看看什么规则");
    return res;
}

}
复制代码
总结
通过三种方式的对比,对于核心部分,其实就是几行代码的不同。无论是利用 Event 事件还是通过 Aware,本质都是拿到或利用 ApplicationContext 去解析接口,拿到实现类的实例,放入集合,然后在客户端(或其他)获取集合,根据枚举标识拿到对应的子类,执行对应的业务逻辑。

你可能感兴趣的:(利用springboot初始化机制三种实现策略模式的应用)