面试时总被问,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<D, R> {
String check(D data, R rule);œ
}
@Service
@Validator(authType = AuthType.B_USER)
public class BUserValidator implements UserValidator<String, String> {
@Overridepublic String check(String data, String rule) { System.out.println("客官,这里B端用户逻辑"); return "";}
}
@Service
@Validator(authType = AuthType.C_USER)
public class CUserValidator implements UserValidator<String, String> {
@Overridepublic 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<ContextRefreshedEvent> {
private ConcurrentHashMap<Integer, UserValidator> validatorMap = new ConcurrentHashMap<>();@Overridepublic 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<Integer, UserValidator> getValidatorMap() { return validatorMap;}
}
复制代码
Api 接口定义如下,依据不同的authType 值,执行不同的auth service
@RequestMapping("/client_auth")
@RestController
public class Client3 {
@Autowiredprivate AuthContainer authContainer;@RequestMapping("getAuth")public String getRule(@RequestParam("authType") Integer authType) { // if authType=1,B_USER; if authType=2,C_USER; ConcurrentHashMap<Integer, UserValidator> 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)办法,基于注解类,获取标有指定注解类的所有实例
代码构造:
外围代码如下:
public abstract class RuleValidator<D, R> {
public abstract String check(D data, R rule);
}
@RuleMapping(ruleCodeEnum = RuleCodeEnum.COUNT)
@Service
public class CountRuleValidator extends RuleValidator<String, String> {
@Overridepublic String check(String data, String rule) { System.out.println("客官,这里是数量规定区域"); return "";}
}
@RuleMapping(ruleCodeEnum = RuleCodeEnum.PRICE)
@Service
public class PriceRuleValidator extends RuleValidator<String, String> {
@Overridepublic 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<Integer, RuleValidator> validatorMap = new HashMap<>();@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.context = applicationContext;}public Map<Integer, RuleValidator> getValidatorMap() { return validatorMap;}@PostConstructpublic 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 {
@Autowiredprivate RuleValidatorInit ruleValidatorInit;@RequestMapping("getRule")public String getRule(@RequestParam("ruleType") Integer ruleType) { Map<Integer, RuleValidator> map = ruleValidatorInit.getValidatorMap(); System.out.println(map); RuleValidator<String, String> ruleValidator = map.get(ruleType); String res = ruleValidator.check("hi", "看看什么规定"); return res;}
}
复制代码
形式三:应用ApplicationContextAware
比照形式一,这里不须要定义指定注解了
外围应用的是 ApplicationContext.getBeansOfType(classType)办法,获取接口 classType 的所有子类实例
代码构造:
外围代码如下:
public interface RoleValidator<D, R> {
String check(D data, R rule);RoleCodeEnum source();
}
@Service
public class BRoleValidator implements RoleValidator<String, String> {
@Overridepublic String check(String data, String rule) { System.out.println("客官,这里B端用户逻辑"); return "";}@Overridepublic RoleCodeEnum source() { return RoleCodeEnum.B_USER;}
}
@Service
public class CRoleValidator implements RoleValidator<String, String> {
@Overridepublic String check(String data, String rule) { System.out.println("客官,这里C端用户逻辑"); return "";}@Overridepublic 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<RoleCodeEnum, RoleValidator> builderMap = new HashMap<>();@Overridepublic 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 {
@Autowiredprivate 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 去解析接口,拿到实现类的实例,放入汇合,而后在客户端(或其余)获取汇合,依据枚举标识拿到对应的子类,执行对应的业务逻辑。