策略模式在实际开发中使用非常频繁的设计模式;
通常都是写完策略类后,还要专门写一个类进行策略分发,比较繁琐;
spring中利用@Autowired注解,可以支持自动注入list、map类型
@Autowired
private Map map;
map的key,是实例bean的beanName;
往往在实际使用过程中,策略key是业务场景类型还不是beanName;
基于注解的方式完成策略模式
通过spring BeanPostProcessor初始化回调,支持自定义map key
show code:
StrategyPattern
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface StrategyPattern {
}
StrategyKey
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface StrategyKey {
String value() default "";
}
StrategyDefault
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface StrategyDefault {
}
StrategyMap
public class StrategyMap extends LinkedHashMap {
@Override
public V get(Object key) {
V v = super.get(key);
return Objects.isNull(v) ? super.get("StrategyDefault") : v;
}
}
自定义StrategyInstantiationAwareBeanPostProcessor
@Component
public class StrategyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
public final static String HELLO_BIKE_PACKAGE = "hello";
public String getScanPackageKeyword() {
return HELLO_BIKE_PACKAGE;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
try {
String packageName = Optional.of(bean)
.map(Object::getClass)
.map(Class::getPackage)
.map(Package::getName)
.orElse(null);
if (!StringUtils.contains(packageName, getScanPackageKeyword())) {
return bean;
}
Field[] declaredFields = bean.getClass().getDeclaredFields();
for (Field declaredField : declaredFields) {
StrategyPattern annotation = AnnotationUtils.findAnnotation(declaredField, StrategyPattern.class);
if (annotation == null) {
continue;
}
if (declaredField.getType() == Map.class) {
ReflectionUtils.makeAccessible(declaredField);
Map strategyMap = (Map) ReflectionUtils.getField(declaredField, bean);
if (MapUtils.isEmpty(strategyMap)) {
log.warn("beanName:{},property:{}, strategy is null", beanName, declaredField.getName());
continue;
}
Map newMap = new StrategyMap<>();
for (Map.Entry entry : strategyMap.entrySet()) {
StrategyKey strategyKey = AnnotationUtils.findAnnotation(entry.getValue().getClass(), StrategyKey.class);
if (strategyKey == null) {
newMap.put(entry.getKey(), entry.getValue());
} else {
newMap.put(strategyKey.value(), entry.getValue());
}
if (AnnotationUtils.findAnnotation(entry.getValue().getClass(), StrategyDefault.class) != null) {
newMap.put("StrategyDefault", entry.getValue());
}
}
ReflectionUtils.setField(declaredField, bean, newMap);
}
}
} catch (Exception e) {
log.error("beanName:{}, strategy pattern init err ", beanName, e);
}
return bean;
}
}
public interface Test {
String test();
}
@Component("Test1")
@StrategyDefault
public class Test1 implements Test {
@Override
public String test() {
return "Test1";
}
}
@Component
@StrategyKey("bean_test2")
public class Test2 implements Test{
@Override
public String test() {
return "Test2";
}
}
@Component
public class UserServiceImpl implements UserService {
@Autowired
@StrategyPattern
private Map map;
@Override
@PostConstruct
public UserDTO getUser() {
UserDTO user = new UserDTO();
user.setUserId(1L);
user.setUserName("zhang san");
user.setAge(18);
System.err.println("==================================" + map.get("Test1").test());
for (Map.Entry stringTestEntry : map.entrySet()) {
System.out.println("key:::::::::::::" + stringTestEntry.getKey());
}
return user;
}
}