Java 反射 抽取類的方法信息

jopen 10年前發布 | 36K 次閱讀 Java 反射 Java開發

目前參與的項目是用 Spring MVC + MyBatis 實現的,項目部署就是一個war包。公司從外面請了個顧問,建議將公司網絡分為A、B兩個區,B區的安全級別高些,可以訪問數據庫,A區的安全級別低些, 不能訪問數據庫,直接面向互聯網,應用需要訪問外部互聯網服務時 或 外部用戶請求應用時都必須在 A 區完成,A區通過定制的網關訪問 B 區的應用。這個建議是強制執行,所以就需要拆分項目了。

考慮到開發的方便性,A區與B區之間就必須工作在類似Hessian之類的遠程調用上,而不能直接在http層上,要不然裝包拆包都累死人了。

項目目前的代碼層次是 Rest 風格的 Controller + Service + MyBatis 的 Mapper。Controller 里大量使用servlet的API,所以不能把controller層抽取出來作為遠程調用的接口。Mapper本身只是一個接口,service層與 mapper層之間沒法再拆,只能在controller與service之間拆。項目里沒有專門為每個 service 組件定義一個相應的接口,需要根據已有的service組件抽取出對應的接口。

由于組件太多,只能寫工具類抽取。

工具類的目標:

  1. 抽取所有組件的公開方法作為接口的方法,保留方法定義的類型信息和參數名等信息。
  2. 生成接口所依賴的導入并拷貝所有依賴的導入類。
  3. 生成對應的Hessian配置。
  4. </ol>

    要保留方法的參數名信息需要 Java 8 的特性。Java 8 的 javac 增加了一個選項 -parameters,表示在生成的字節碼文件里保留方法的參數名。

    具體源碼

    package net.coderbee.demo.util;
    import java.io.Closeable;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.lang.reflect.Method;
    import java.lang.reflect.Parameter;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.LinkedList;
    import java.util.List;
    /**

    • 把指定類型的公開方法抽取出來,生成一個名為("I" + 類名)的接口的源碼,包路徑相同,并拷貝所依賴的項目源碼。
    • @author coderbee / public class InterfaceExtractor { /**
      • 要跳過的方法名 */ private final List<String> FILTER_METHOD = Arrays.asList("wait", "equals",
            "toString", "hashCode", "getClass", "notify", "notifyAll", "main");
        
        /**
      • 不需要導入的基本類型 */ private static final List<String> FILTER_TYPE = Arrays.asList("boolean",
            "char", "byte", "int", "short", "double", "float", "long", "void");
        
        private String srcDir; // 源碼目錄 private String dstDir; // 生成代碼的存放目錄 // 保存要導入的類型 private List<String> imports = new LinkedList<String>(); // 生成的接口源碼 private StringBuilder bodyBuilder = new StringBuilder(1024); /**
      • @param srcDir
      • 源碼目錄
      • @param dstDir
      • 生成代碼的存放目錄 */ public InterfaceExtractor(String srcDir, String dstDir) { this.srcDir = srcDir; this.dstDir = dstDir; } /**
      • 抽取指定類型的接口
      • @param claz
      • 表示類的 Class 實例 */ public void extractInterface(@SuppressWarnings("rawtypes") Class claz) { String fullName = getNormalName(claz); String path = getPkgPath(fullName); String pkg = "package " + path + ";\n\n"; bodyBuilder.append("public interface I").append(claz.getSimpleName()) .append(" {\n"); Method[] methods = claz.getMethods(); for (Method method : methods) { if (!FILTER_METHOD.contains(method.getName())) { addMethod(bodyBuilder, method); bodyBuilder.append('\n'); } } bodyBuilder.setCharAt(bodyBuilder.length() - 1, '}'); writeFileD(dstDir + getIName(fullName) + ".java", pkg + getImports()
        • "\n" + bodyBuilder); } private void copyImports(String type) { String subPath = File.separatorChar
        • type.replace('.', File.separatorChar) + ".java"; File srcFile = new File(srcDir + subPath); if (srcFile.exists()) { File dstFile = new File(dstDir + subPath); copy(srcFile, dstFile); } } private String getImports() { Collections.sort(imports); StringBuilder importBuilder = new StringBuilder(1024); for (String imp : imports) { importBuilder.append("import ").append(imp).append(";\n"); copyImports(imp); } return importBuilder.toString(); } /**
      • 添加一個方法的聲明
      • @param sb
      • @param method */ private void addMethod(StringBuilder sb, Method method) { bodyBuilder.append('\t'); addReturnType(method); bodyBuilder.append(' ').append(method.getName()).append('('); // 添加方法名 addParameter(method); bodyBuilder.append(");\n"); } /**
      • 添加方法的參數
      • @param sb
      • @param method */ private void addParameter(Method method) { Type[] paramTypeList = method.getGenericParameterTypes(); Parameter[] parameters = method.getParameters(); for (int i = 0; i < parameters.length; i++) {
            Type paramType = paramTypeList[i];
            addTypeParameters(paramType);
            Parameter parameter = parameters[i];
            bodyBuilder.append(' ').append(parameter.getName());
            if (i != parameters.length - 1) {
                 bodyBuilder.append(", ");
            }
        
        } } private String getTypeName(Type type) { if (type instanceof ParameterizedType) {
            // 泛型
            return getGenericTypeName((ParameterizedType) type);
        
        } else {
            // 非泛型
            return getSimpleTypeName(type.getTypeName());
        
        } } private String getGenericTypeName(ParameterizedType type) { Type[] actualTypeArguments = type.getActualTypeArguments(); if (actualTypeArguments == null || actualTypeArguments.length == 0) {
            // 泛型的類型非參數化的
            return getSimpleTypeName(type.getTypeName());
        
        } else {
            StringBuilder sb = new StringBuilder(64);
            String typeName = genericRawType(type.getTypeName());
            sb.append(getSimpleTypeName(typeName));
            sb.append('<');
            for (Type genericType : actualTypeArguments) {
                 sb.append(getTypeName(genericType)).append(", ");
            }
            sb.setCharAt(sb.length() - 2, '>');
            return sb.deleteCharAt(sb.length() - 1).toString();
        
        } } private String genericRawType(String typeName) { int indexOf = typeName.indexOf('<'); return typeName.substring(0, indexOf); } private String getSimpleTypeName(String typeName) { if (typeName.startsWith("[")) {
            // 返回的類型是數組
            return getArrayTypeName(typeName);
        
        } return getSimpleNameByFullName(typeName); } private String getArrayTypeName(String typeName) { // 第二個字符表示數組元素的類型 char ch = typeName.charAt(1); if (ch == 'Z') {
            return "boolean[]";
        
        } else if (ch == 'B') {
            return "byte[]";
        
        } else if (ch == 'C') {
            return "char[]";
        
        } else if (ch == 'S') {
            return "short[]";
        
        } else if (ch == 'I') {
            return "int[]";
        
        } else if (ch == 'F') {
            return "float[]";
        
        } else if (ch == 'D') {
            return "double[]";
        
        } else if (ch == 'J') {
            return "long[]";
        
        } else if (ch == 'L') {
            // 對象數組
            String tName = typeName.substring(2, typeName.indexOf(';'));
            return getSimpleNameByFullName(tName) + "[]";
        
        } else {
            return "";
        
        } } /**
      • 通過類完整路徑名獲取類的簡單名字,并加入導入列表。
      • @param fullName
      • 類完整路徑名
      • @return 簡單名字 */ private String getSimpleNameByFullName(String fullName) { String[] split = fullName.split("\."); if (split.length == 3 && fullName.startsWith("java.lang.")) {
            // java.lang 包下的不需要顯式 import
            return split[2];
        
        } else {
            if (!FILTER_TYPE.contains(fullName) && fullName.length() > 1
                      && !imports.contains(fullName) && !fullName.contains("[")) {
                 // 過濾數組參數類型(如:int[] )
                 imports.add(fullName);
            }
            return split[split.length - 1];
        
        } } /**
      • 添加方法的返回類型
      • @param sb
      • @param method */ private void addReturnType(Method method) { if (method.getName().endsWith("getDeuAmoArr")) {
            System.out.println("hold");
        
        } Type genericReturnType = method.getGenericReturnType(); if (genericReturnType instanceof ParameterizedType) {
            // 泛型
            String typeName = getGenericTypeName((ParameterizedType) genericReturnType);
            bodyBuilder.append(typeName);
        
        } else {
            // 非泛型
            Class<?> returnType = method.getReturnType();
            String returnTypeName = getSimpleTypeName(returnType.getName());
            bodyBuilder.append(returnTypeName);
        
        } } /**
      • 添加泛型的實際類型
      • @param sb
      • @param type
      • 返回類型或方法參數的類型 */ private void addTypeParameters(Type type) { String typeName = type.getTypeName(); if (type instanceof ParameterizedType) { bodyBuilder.append(getGenericTypeName((ParameterizedType) type)); } else { String[] split = typeName.split(" ", 2); if (split.length > 1) { bodyBuilder.append(split[1]); } else { bodyBuilder.append(getSimpleTypeName(typeName)); } } } /**
      • 獲取 包 路徑
      • @param fullName
      • @return */ private String getPkgPath(String fullName) { int i = fullName.lastIndexOf('.'); return fullName.substring(0, i); } /**
      • 獲取代碼所聲明的類的完整路徑名
      • @param claz
      • @return */ private String getNormalName(@SuppressWarnings("rawtypes") Class claz) { String name = claz.getName(); int i = name.indexOf('$'); if (i != -1) {
            name = name.substring(0, i);
        
        } return name; } private static String getIName(String fullName) { String[] split = fullName.split("\."); StringBuilder sb = new StringBuilder(fullName.length()); for (int i = 0; i < split.length - 1; i++) {
            sb.append(split[i]).append(File.separatorChar);
        
        } sb.append('I').append(split[split.length - 1]); return sb.toString(); } public static void writeFileD(String fullPath, String body) { FileOutputStream fout = null; try {
            File file = new File(fullPath);
            if (!file.getParentFile().exists()) {
                 file.getParentFile().mkdirs();
            }
            fout = new FileOutputStream(file);
            fout.write(body.getBytes("UTF-8"));
        
        } catch (IOException e) {
            e.printStackTrace();
        
        } finally {
            closeQuietly(fout);
        
        } } private void copy(File srcFile, File dstFile) { File dstDir = dstFile.getParentFile(); if (!dstDir.exists()) {
            dstDir.mkdirs();
        
        } FileInputStream inputStream = null; FileOutputStream outputStream = null; try {
            inputStream = new FileInputStream(srcFile);
            outputStream = new FileOutputStream(dstFile);
            inputStream.getChannel().transferTo(0, srcFile.length(),
                      outputStream.getChannel());
        
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        
        } catch (IOException e) {
            e.printStackTrace();
        
        } finally {
            closeQuietly(inputStream);
            closeQuietly(outputStream);
        
        } } public static void closeQuietly(Closeable closeable) { if (closeable != null) {
            try {
                 closeable.close();
            } catch (IOException ignored) {
            }
        
        } } }</pre>
 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!