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:\woorkspace\servletdemo\javaweb-servlet-demo\build\classes
        // 使用 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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM