一般使用策略模式的时候,经常使用xml、enum或者map先将策略的以key-value的形式存储起来,然后配置一个策略选择器,根据传入的参数去找到具体的策略实现类。此种方法比较简单,确实是很多情况的首选,但是如果想减少配置,每次增加一个策略只需要写一个实现类,在实现类上标记下注解就结束了,此处推荐扫描自定义注解,项目启动时依赖spring加载计划,动态加载到策略的上下文。具体实现如下:
1.自定义注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface HandleType {
String value();
}
2.自定义扫描器
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
public class ClassScanner {
private final Logger logger = LoggerFactory.getLogger(getClass());
private static final String RESOURCE_PATTERN = "**/%s/**/*.class";
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
public ClassScanner(){
}
@SafeVarargs
public final Set<Class<?>> scan(String[] confPkgs, Class<? extends Annotation>... annotationTags){
Set<Class<?>> resClazzSet = new HashSet<>();
List<AnnotationTypeFilter> typeFilters = new LinkedList<>();
if (annotationTags != null){
for (Class<? extends Annotation> annotation : annotationTags) {
typeFilters.add(new AnnotationTypeFilter(annotation, false));
}
}
if (confPkgs != null && confPkgs.length > 0) {
for (String pkg : confPkgs) {
String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + String.format(RESOURCE_PATTERN, ClassUtils.convertClassNameToResourcePath(pkg));
try {
Resource[] resources = this.resourcePatternResolver.getResources(pattern);
MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(this.resourcePatternResolver);
for (Resource resource : resources) {
if (resource.isReadable()) {
MetadataReader reader = readerFactory.getMetadataReader(resource);
String className = reader.getClassMetadata().getClassName();
if (ifMatchesEntityType(reader, readerFactory,typeFilters)) {
Class<?> curClass = Thread.currentThread().getContextClassLoader().loadClass(className);
resClazzSet.add(curClass);
}
}
}
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
}
}
return resClazzSet;
}
/**
* 检查当前扫描到的类是否含有任何一个指定的注解标记
* @param reader
* @param readerFactory
* @return ture/false
*/
private boolean ifMatchesEntityType(MetadataReader reader, MetadataReaderFactory readerFactory,List<AnnotationTypeFilter> typeFilters) {
if (!CollectionUtils.isEmpty(typeFilters)) {
for (TypeFilter filter : typeFilters) {
try {
if (filter.match(reader, readerFactory)) {
return true;
}
} catch (IOException e) {
logger.error("过滤匹配类型时出错 {}",e.getMessage());
}
}
}
return false;
}
}
3.利用spring后置处理器装载
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@Component
public class HandleTypeAnnotationBeanPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
ClassScanner classScanner = new ClassScanner();
Set<Class<?>> classSet = classScanner.scan(new String[]{"demo.handler"}, HandleType.class);
Map<String, Class> handleMap = new HashMap<>();
for (Class clazz : classSet) {
HandleType handleType = (HandleType) clazz.getAnnotation(HandleType.class);
handleMap.put(handleType.value(), clazz);
}
HandlerContext handlerContext = new HandlerContext(handleMap);
beanFactory.registerSingleton(HandlerContext.class.getName(), handlerContext);
}
}
4.策略处理器上下文
import java.util.Map;
public class HandlerContext {
private Map<String, Class> handlerMap;
public HandlerContext(Map<String, Class> handlerMap) {
this.handlerMap = handlerMap;
}
public HandlerContext() {
}
public AbstractRiskHandler getInstance(String type) {
Class clazz = handlerMap.get(type);
return (AbstractRiskHandler) SpringContextUtil.getBean(clazz);
}
}
5.抽象策略处理器类
public abstract class AbstractRiskHandler {
public String handle(String req) {
buildSceneData(req);
return null;
}
protected abstract void buildSceneData(String req);
}
6.具体策略实现类
import org.springframework.stereotype.Component;
@Component
@HandleType("risk1")
public class Risk1Handler extends AbstractRiskHandler {
@Override
protected void buildSceneData(String req) {
System.out.println("场景1");
}
}
7.测试类
class Test{
@Autowire
HandlerContext handlerContext
@Test
public void test(){
handlerContext.getInstance("risk1").handle("test");
}
}
网友评论