zoukankan      html  css  js  c++  java
  • Java 扫描实现 Ioc 动态注入,过滤器根据访问url调用自定义注解标记的类及其方法

    扫描实现 Ioc 动态注入

    参考:

    http://www.private-blog.com/2017/11/16/java-%e6%89%ab%e6%8f%8f%e5%ae%9e%e7%8e%b0-ioc-%e5%8a%a8%e6%80%81%e6%b3%a8%e5%85%a5/

    实现思路:

    1.首先要通过 IO 去找到指定的路径(当前类的全路径)下的所有的 class文件;

    2.通过反射机制 使用文件的全路径来 初始化对象;

    3.接下来判断这个对象是否有使用了自定义的注解,如果有就保存到 classMap (类容器)中缓存起来;

    4.类保存好以后在把方法的名称也 缓存到 methodMap(方法容器)中,方便反射调用。

    实体bean的注解类

    /**
     * 自定义注解
     */
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME) /** 这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用. */
    @Target(ElementType.TYPE) /** 此注解应用于 类上. */
    @Documented /** 注解表明这个注解应该被 javadoc工具记录. */
    public @interface CustomAnnotationBean {
        /**
         * 描述
         */
        String description() default "";
    }

    实体bean的方法的注解类

    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    /**
     * 自定义注解
     */
    @Retention(RetentionPolicy.RUNTIME) /** 这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用. */
    @Target(ElementType.METHOD) /** 此注解应用于 方法上. */
    @Documented /** 注解表明这个注解应该被 javadoc工具记录. */
    public @interface CustomAnnotationMethod {
         /**
         * 描述
         */
        String description() default "";
    
        /**
         * 访问路径
         *
         * @return
         */
        String uri();
    }

    实体beanT1

    @CustomAnnotationBean
    public class T1 {
        private String id;
    
        private String name;
    
        @CustomAnnotationMethod(uri = "t1/getId")
        public String getId() {
            System.out.println("进入==========t1/getId=========方法");
            return id;
        }
    
        public void setId(String id) {
    
            this.id = id;
        }
    
        @CustomAnnotationMethod(uri = "t1/getName")
        public String getName() {
    
            System.out.println("进入==========t1/getName=========方法");
            return name;
        }
    
        public void setName(String name) {
    
            this.name = name;
        }
    }

    实体beanT2

    @CustomAnnotationBean
    public class T2 {
        private String id;
    
        private String name;
    
        @CustomAnnotationMethod(uri = "t2/getId")
        public String getId() {
            System.out.println("进入==========t2/getId=========方法");
            return id;
        }
    
        public void setId(String id) {
    
            this.id = id;
        }
    
        @CustomAnnotationMethod(uri = "t2/getName")
        public String getName() {
    
            System.out.println("进入==========t2/getName=========方法");
            return name;
        }
    
        public void setName(String name) {
    
            this.name = name;
        }
    }

    扫描类

    import java.io.File;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.Enumeration;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 扫描类
     *
     * @author Administrator
     *
     */
    public class JavaScan {
        /**
         * 存放 文件根路径
         */
        static String classPath;
    
        /**
         * 存放结果
         */
        static List<String> classPathList = new ArrayList<>();
    
        /**
         * 使用类全名定义的bean容器
         */
        static Map<String, Class<?>> beans = new HashMap<>();
    
        /**
         * 使用方法的注解的url属性定义的classes容器
         */
        static Map<String, Class<?>> classes = new HashMap<>();
    
        /**
         * method 容器
         */
        static Map<String, Method> methods = new HashMap<>();
    
        /**
         * 初始化
         *
         * @return
         * @throws Exception
         */
        public static void init(String path) throws Exception {
            if (null == path)
                throw new NullPointerException("JavaScan.init(String path) 参数不能为null");
            // 初始化 获取项目的 classPath 路径,File.separator:
            classPath = new File(getRootPath()).getPath() + File.separator;
            // 总结:String classPathNoseparator = new File(rootPath).getPath()
            // 结果:G:woorkspaceservletdemojavaweb-servlet-demouildclasses
            // 使用 IO扫描 指定路径下的所有文件
            getFileName(classPath + path);
            // 使用 所有类命名字符串来 初始化容器
            initContainer();
        }
    
        /**
         * 获取rootPath的相关的根路径<br>
         * getResources("") 如果放为空串儿,那么就是获取rootPath的相关的根路径
         *
         * @return rootPath的相关的根路径
         * @throws Exception
         */
        private static String getRootPath() throws Exception {
            // 注: main方法启动 获取路径方式
    //        Enumeration<URL> resources = JavaScan.class.getClassLoader().getResources("");
            // 注: servlet启动 获取路径方式
            Enumeration<URL> resources = JavaScan.class.getClassLoader().getResources("/");
            URL url = resources.nextElement();
            return url.getPath();
            // 总结:String rootPath = this.getClass().getClassLoader().getResources("").nextElement().getPath()
            // 结果:/G:/woorkspace/servletdemo/javaweb-servlet-demo/build/classes/
        }
    
        /**
         * 使用 IO扫描 Class文件
         */
        private static void getFileName(String rootPath) {
            File file = new File(rootPath);
            // 获取所有文件和文件夹
            File[] fileList = file.listFiles();
            for (int i = 0; null != fileList && i < fileList.length; i++) {
                String path = fileList[i].getPath();
                // 如果是目录
                if (fileList[i].isDirectory()) {
                    // 继续递归
                    getFileName(path);
                }
                if (fileList[i].isFile()) {
                    // 输出 所有文件夹下的全路径
                    // System.out.println(path);
                    // 拼接类路径保存到集合中,(类路径所指的是 去掉根路径以外的项目中 class的全路径)
                    // path.replace(fileRootPath, "") 去除根路径
                    // .replaceAll(".class", "") 去掉后缀名
                    // .replaceAll(File.separator + File.separator, ".") 将斜杠'或/'转成
                    // 点'.'
                    String classpath = path.replace(classPath, "").replaceAll(".class", "")
                            .replaceAll(File.separator + File.separator, ".");
                    classPathList.add(classpath);
                }
            }
        }
    
        /**
         * 使用 所有类全命名来 初始化容器
         *
         * @throws Exception
         */
        private static void initContainer() throws Exception {
    
            if (null == classPathList || classPathList.size() <= 0)
                throw new Exception("文件路径不存在!" + JavaScan.class.getName());
    
            // 获取 所有类的类全名
            for (int i = 0; i < classPathList.size(); i++) {
    
                String className = classPathList.get(i);
                Class<?> forName = Class.forName(className);
    
                // 初始化限制,初始化的文件类型必须是 class文件
                if (!forName.isAnnotation() && !forName.isEnum() && !forName.isInterface()) {
    
                    // 只初始化 实现了CustomAnnotationBean注解的类
                    if (forName.isAnnotationPresent(CustomAnnotationBean.class)) {
                        // 初始化类对象 添加到容器中
                        if (!beans.containsKey(className))
                            beans.put(className, forName);
                    }
    
                    // 只初始化 实现了CustomAnnotationBean注解的类中的方法
                    Method[] methodArray = forName.getDeclaredMethods();
                    for (Method method : methodArray) {
                        // 初始化 实现了CustomAnnotationMethod注解的方法
                        if (method.isAnnotationPresent(CustomAnnotationMethod.class)) {
                            // 获取注解
                            CustomAnnotationMethod annotation = method.getAnnotation(CustomAnnotationMethod.class);
                            // 获取注解的属性
                            String attr = annotation.uri();
                            if (!methods.containsKey(attr)) {
                                // 初始化方法 添加到容器中
                                methods.put(attr, method);
                                // 将此方法对应的类 添加到容器中
                                classes.put(attr, forName);
                            }
                        }
                    }
                }
            }
        }
    
        /**
         * 执行 method
         *
         * @param url
         * @return
         * @throws InvocationTargetException
         * @throws IllegalAccessException
         * @throws InstantiationException
         * @throws IllegalArgumentException
         */
        public Object executeMethod(String url, Object... args)
                throws InvocationTargetException, IllegalAccessException, IllegalArgumentException, InstantiationException {
            if (null == url || "".equals(url))
                throw new NullPointerException("ApiPool.executeMethod(String url):参数不能为null");
            return methods.get(url).invoke(classes.get(url).newInstance(), args);
        }
    
        /**
         * 获取 使用类全名定义的bean容器
         *
         * @return
         */
        public Map<String, Class<?>> getBeans() {
    
            return beans;
        }
    
        /**
         * 获取 使用类全名定义的bean
         *
         * @return
         */
        public Class<?> getBean(String key) {
    
            return beans.get(key);
        }
    
        /**
         * 获取 使用方法的注解的url属性定义的classes容器
         *
         * @return
         */
        public Map<String, Class<?>> getClazzs() {
    
            return classes;
        }
    
        /**
         * 获取 使用方法的注解的url属性定义的classes
         *
         * @return
         */
        public Class<?> getClazz(String key) {
    
            return classes.get(key);
        }
    
        /**
         * 获取Method容器
         *
         * @return
         */
        public Map<String, Method> getMethods() {
    
            return methods;
        }
    
        /**
         * 获取Method
         *
         * @return
         */
        public Method getMethod(String key) {
    
            return methods.get(key);
        }
    
        /**
         * 测试
         *
         * @param args
         * @throws Exception
         */
        public static void main(String[] args) throws Exception {
    
            JavaScan javaScan = new JavaScan();
            // 在main 方法中调用传空串就可以
            javaScan.init("");
    
            for (String key : javaScan.getBeans().keySet()) {
                Object object = javaScan.getBean(key);
                System.out.println(object);
            }
        }
    }
    View Code

    过滤器

    import java.io.IOException;
    import java.io.PrintWriter;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Map;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.json.JSONObject;
    
    public class AnnotationHandleFilter implements Filter {
        private ServletContext servletContext = null;
    
        @Override
        public void destroy() {
            // TODO Auto-generated method stub
    
        }
    
        @Override
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            System.out.println("---进入注解处理过滤器---");
            // 将ServletRequest强制转换成HttpServletRequest
            HttpServletRequest req = (HttpServletRequest) request;
            HttpServletResponse res = (HttpServletResponse) response;
            // 初始化方法init()中注入类的容器
            Map<String, Class<?>> classMap = (Map<String, Class<?>>) servletContext.getAttribute("servletClassMap");
            // 获取contextPath:/javaweb-servlet-demo
            String contextPath = req.getContextPath();
            // 获取用户请求的URI资源:/javaweb-servlet-demo/t1/getId
            String uri = req.getRequestURI();
            // 截取项目名后的uri如有的话:t1/getId
            String reqUri = uri.substring(contextPath.length() + 1);
            // 如果请求了某种带自定义注解的类的方法
            if (!"".equals(reqUri)) {
                // 获取要使用的类
                Class<?> clazz = classMap.get(reqUri);
                // 创建类的实例
                Method[] methods = clazz.getMethods();
                // 循环执行方法
                for (Method method : methods) {
                    if (method.getName().contains("get")) {
                        try {
                            // 创建类的实例
                            Object o = clazz.newInstance();
                            // 执行方法
                            method.invoke(o);
                        } catch (InstantiationException | IllegalAccessException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        } catch (IllegalArgumentException | InvocationTargetException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                }
            }
            // 返回页面
            res.setCharacterEncoding("UTF-8");
            res.setContentType("application/json; charset=utf-8");
            PrintWriter out = null;
            // 返回json对象
            JSONObject json = new JSONObject();
            try {
                // 返回json
                json.put("code", "200");
                json.put("msg", "执行成功");
                out = res.getWriter();
                out.append(json.toString());
            } catch (Exception e) {
                e.printStackTrace();
                res.sendError(500);
            }
        }
    
        @Override
        public void init(FilterConfig filterConfig) throws ServletException {
            System.out.println("---AnnotationHandleFilter过滤器初始化开始---");
            servletContext = filterConfig.getServletContext();
            Map<String, Class<?>> classMap = new HashMap<String, Class<?>>();
            addServletClassToServletContext(classMap);
            System.out.println("----AnnotationHandleFilter过滤器初始化结束---");
        }
    
        private void addServletClassToServletContext(Map<String, Class<?>> classMap) {
            try {
                JavaScan.init("");
                Map<String, Class<?>> classes = JavaScan.classes;
                for (Map.Entry<String, Class<?>> entry : classes.entrySet()) {
                    String key = entry.getKey();
                    Class<?> value = entry.getValue();
                    System.out.println("Key = " + key + ", Value = " + value);
                    classMap.put(key, value);
                    servletContext.setAttribute("servletClassMap", classMap);
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
        }
    }
    View Code

    web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns="http://java.sun.com/xml/ns/javaee"
        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
        id="WebApp_ID" version="3.0">
        <display-name>javaweb-servlet-demo</display-name>
        <welcome-file-list>
            <welcome-file>index.html</welcome-file>
        </welcome-file-list>
        <!-- <servlet>
            <servlet-name>ServletDemo</servlet-name>
            <servlet-class>com.demo.ServletDemo</servlet-class>
        </servlet>
        <servlet-mapping>
            <servlet-name>ServletDemo</servlet-name>
            <url-pattern>/servlet/ServletDemo</url-pattern>
        </servlet-mapping> -->
        <filter>
            <description>注解处理过滤器</description>
            <filter-name>AnnotationHandleFilter</filter-name>
            <filter-class>com.demo.AnnotationHandleFilter</filter-class>
            <init-param>
                <description>配置要扫描包及其子包, 如果有多个包,以逗号分隔</description>
                <param-name>basePackage</param-name>
                <param-value>com.demo</param-value>
            </init-param>
        </filter>
    
        <filter-mapping>
            <filter-name>AnnotationHandleFilter</filter-name>
            <!-- 拦截后缀是.do的请求 -->
            <!-- <url-pattern>*.do</url-pattern> -->
            <url-pattern>/*</url-pattern>
        </filter-mapping>
    </web-app>
    View Code

    git地址:

    https://github.com/yuki9467/javaweb-scanner-demo

  • 相关阅读:
    扩展一些std::string未提供的常用方法
    Qt子线程中显示窗口部件的一个方法
    Qt子线程中通过QMetaObject::invokeMethod刷新UI控件
    “我的一剂良药”之开源指北
    源码解析之 Mybatis 对 Integer 参数做了什么手脚?
    必知必会面试题之 Spring 基础
    从一部电影史上的趣事了解 Spring 中的循环依赖问题
    Mysql、Oracle、SQL-Server 查询字段值长度
    Cross-Origin Read Blocking (CORB) blocked cross-origin response 问题
    MacOS11.0-brew 卡在Updating Homebrew
  • 原文地址:https://www.cnblogs.com/yuki67/p/9512046.html
Copyright © 2011-2022 走看看