反射----拈花指

本文介绍如何通过反射机制和BeanFactoryPostProcessor接口在Spring框架中动态注册和使用自定义处理器,实现根据类型代码调用不同处理逻辑的RPC路由功能。

前言

怎么进一步用反射,在BeanFactoryPostProcessor 做做文章    
## 调用
 public void testRpcRouter(String methodTyep,String typeCode) throws Exception {

        DemoDO demoDO = new DemoDO();
        AbstractHandler abstractHandler = handlerContext.getInstance(typeCode);
        abstractHandler.rpc(demoDO);

        //利用 方法上的 注解,指定执行的方法
        Method method = handlerContext.getMethodInstance(methodTyep);
        method.invoke(new MethodList(), demoDO);
    }

加载

@Component
public class HandlerProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        Map<String, Class> map = Maps.newHashMapWithExpectedSize(2);
        Map<String, Method> methodMap = Maps.newHashMapWithExpectedSize(2);

        List<Class<?>> scan =AnnotationScannerUtils.scan("com.domain.cls", HandlerType.class);
        for (Class<?> clazz : scan) {
            String type = ((HandlerType) clazz.getAnnotation(HandlerType.class)).value();
            map.put(type, clazz);
        }

        List<Method> methods =AnnotationScannerUtils.scanMethodByAnnotation(MethodList.class, MethodType.class);
        for (Method item : methods) {
            String type = ((MethodType) item.getAnnotation(MethodType.class)).value();
            methodMap.put(type, item);

        }
        configurableListableBeanFactory.registerResolvableDependency(HandlerContext.class, new HandlerContext(map, methodMap));
    }
}

自定义的注解

@Documented
@Inherited
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodType {
    String value();
}

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

    String value();

}

容器


public class HandlerContext {

    private Map<String, Class> map;

    private Map<String, Method> methodMap;

    public HandlerContext(Map<String, Class> map, Map<String, Method> methodMap) {
        this.map = map;
        this.methodMap = methodMap;
    }

    public  AbstractHandler getInstance(String type) {
        Class c = map.get(type);
        return ( AbstractHandler) SpringFactoryUtil.getBean(c);
    }

    public Method getMethodInstance(String type) {
        Method c = methodMap.get(type);
        return c;
    }

}

扫描

package com.ly.fn.xxd.srv.domain;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;

public class AnnotationScannerUtils {
    private static final Logger logger = LoggerFactory.getLogger(com.ly.fn.xxd.srv.domain.AnnotationScannerUtils.class);
    private static final String EXT = "class";


    /**
     * 项目在硬盘上的基础路径
     */
    private static final String PROJECT_PATH = System.getProperty("user.dir");// xxd\IdeaProjects\offers
    /**
     * 获取当前类的路径 com.example.CodeGenerator.core
     */
    private static String packAge = com.ly.fn.xxd.srv.domain.AnnotationScannerUtils.class.getPackage().getName();
    /**
     * 根据路径切割最后一位名称获得当前类上一级路径 com.example.CodeGenerator
     */
    private static final String PACKAGE = packAge.substring(0, packAge.lastIndexOf("."));


    /**
     * 自定义方法
     * 将获取到的包路径中的点号换成斜杠
     *
     * @param packageName 传入的包路径
     * @return 路径前后都加上斜杠中间也替换成斜杠返回
     */
    private static String packageConvertPath(String packageName) {
        return String.format("/%s/", packageName.contains(".") ? packageName.replaceAll("\\.", "/") : packageName);
    }


    /**
     * 根据包名获取包的URL
     *
     * @param pkgName com.demo.controller
     * @return
     */
    public static String getPkgPath(String pkgName) {
        String pkgDirName = pkgName.replaceAll("\\.", "/");
        URL url = Thread.currentThread().getContextClassLoader().getResource(pkgDirName);

        return url == null ? null : url.getFile();
    }


    public static List<Class<?>> scan(String pkgName, Class<? extends Annotation> Annotation) {
        Set<Class<?>> set = scanClasses(pkgName, getPkgPath(pkgName), false);
        List<Class<?>> result = new ArrayList<>();
        for (Class<?> aClass : set) {
            if (aClass.isAnnotationPresent(Annotation)) {
                result.add(aClass);
            }
        }
        return result;
    }


    /**
     * 获取指定包下所有类对象的集合
     *
     * @param pkgName   包名(com.demo.controller)
     * @param pkgPath   包路径(/Users/xxx/workspace/java/project/out/production/classes/com/demo/controller)
     * @param recursive 是否递归遍历子目录
     * @return 类集合
     */
    public static Set<Class<?>> scanClasses(String pkgName, String pkgPath, final boolean recursive) {
        Set<Class<?>> classesSet = new HashSet<>();

        Collection<File> allClassFile = getAllClassFile(pkgPath, recursive);


        for (File curFile : allClassFile) {
            try {
                classesSet.add(getClassObj(curFile, pkgPath, pkgName));
            } catch (ClassNotFoundException e) {
                logger.error("load class fail", e);
            }
        }

        return classesSet;
    }

    /**
     * 获取指定包下包含指定注解的所有类对象的集合
     *
     * @param pkgName           包名(com.demo.controller)
     * @param pkgPath           包路径(/Users/xxx/workspace/java/project/out/production/classes/com/demo/controller)
     * @param recursive         是否递归遍历子目录
     * @param targetAnnotations 指定注解
     * @return 以注解和对应类集合构成的键值对
     */
    public static Map<Class<? extends Annotation>, Set<Class<?>>> scanClassesByAnnotations(
            String pkgName, String pkgPath, final boolean recursive, List<Class<? extends Annotation>> targetAnnotations) {
        Map<Class<? extends Annotation>, Set<Class<?>>> resultMap = new HashMap<>(16);

        Collection<File> allClassFile = getAllClassFile(pkgPath, recursive);

        for (File curFile : allClassFile) {
            try {
                Class<?> curClass = getClassObj(curFile, pkgPath, pkgName);
                for (Class<? extends Annotation> annotation : targetAnnotations) {
                    if (curClass.isAnnotationPresent(annotation)) {
                        if (!resultMap.containsKey(annotation)) {
                            resultMap.put(annotation, new HashSet<Class<?>>());
                        }
                        resultMap.get(annotation).add(curClass);
                    }
                }
            } catch (ClassNotFoundException e) {
                logger.error("load class fail", e);
            }
        }

        return resultMap;
    }

    /**
     * 加载类
     *
     * @param file
     * @param pkgPath
     * @param pkgName
     * @return
     * @throws ClassNotFoundException
     */
    private static Class<?> getClassObj(File file, String pkgPath, String pkgName) throws ClassNotFoundException {
        // 考虑class文件在子目录中的情况
        String absPath = file.getAbsolutePath().substring(0, file.getAbsolutePath().length() - EXT.length() - 1);
        String className = absPath.substring(pkgPath.length()).replace(File.separatorChar, '.');
        className = className.startsWith(".") ? pkgName + className : pkgName + "." + className;

        return Thread.currentThread().getContextClassLoader().loadClass(className);
    }

    /**
     * 遍历指定目录下所有扩展名为class的文件
     *
     * @param pkgPath   包目录
     * @param recursive 是否递归遍历子目录
     * @return
     */
    private static Collection<File> getAllClassFile(String pkgPath, boolean recursive) {
        File fPkgDir = new File(pkgPath);

        if (!(fPkgDir.exists() && fPkgDir.isDirectory())) {
            logger.error("the directory to package is empty: {}", pkgPath);

            return null;
        }

        return FileUtils.listFiles(fPkgDir, new String[]{EXT}, recursive);
    }

    /**
     * 查找指定注解的Method
     *
     * @param classes    查找范围
     * @param annotation 指定的注解
     * @return 以注解和对应Method类集合构成的键值对
     */
    public static List<Method> scanMethodByAnnotation(Class<?> classes, Class<? extends Annotation> annotation) {
        List<Method> list = new ArrayList<>();
        Method[] methods = classes.getMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(annotation)) {
                list.add(method);
            }
        }
        return list;
    }


    /**
     * 查找指定注解的Method
     *
     * @param classes           查找范围
     * @param targetAnnotations 指定的注解
     * @return 以注解和对应Method类集合构成的键值对
     */
    public static Map<Class<? extends Annotation>, Set<Method>> scanMethodsByAnnotations(Set<Class<?>> classes,
                                                                                         List<Class<? extends Annotation>> targetAnnotations) {
        Map<Class<? extends Annotation>, Set<Method>> resultMap = new HashMap<>(16);

        for (Class<?> cls : classes) {
            Method[] methods = cls.getMethods();

            for (Class<? extends Annotation> annotation : targetAnnotations) {
                for (Method method : methods) {
                    if (method.isAnnotationPresent(annotation)) {
                        if (!resultMap.containsKey(annotation)) {
                            resultMap.put(annotation, new HashSet<Method>());
                        }
                        resultMap.get(annotation).add(method);
                    }
                }
            }
        }

        return resultMap;
    }
}

具体实现类

方法级别

类级别

在这里插入图片描述

整体

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值