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

原文地址:https://www.cnblogs.com/yuki67/p/9512046.html