Java 基於上傳的jar進行反射生成物件

dagecao發表於2020-11-10

最近專案上有個新需求,使用者上傳的jar包,然後解析jar包中指定的類的指定方法的請求引數和返回引數,這裡做一個簡單的記錄,以後可以基於這個demo進行擴充套件

建立一個SpringBoot 的web專案,專案整合了swagger  和 lombok

controller編寫:

controller 很簡單 主要是實現檔案的上傳

@RestController
@RequestMapping("/upload")
@Api(tags = "FileUploadController")
public class FileUploadController {
    private static final Logger logger = LoggerFactory.getLogger(FileUploadController.class);

    @Value("${mvp.fileupload.path}")
    private String filepath;

    @Autowired
    private ParamParseService paramParseService;

    @PostMapping(value = "")
    @ApiOperation(value = "上傳文件", notes="上傳jar並解析")
    public String upload(@RequestParam(value = "file") MultipartFile file,
        @RequestParam String service,
        @RequestParam String method)throws Exception{
        byte[] bytes = file.getBytes();

        ParamParseDTO paramParseDTO = new ParamParseDTOBuilder().jar(bytes)
            .jarName(file.getOriginalFilename()).path(filepath)
            .service(service).method(method).build();

        paramParseService.parseJar(paramParseDTO);
        logger.info("解析成功!");
        return "parse success";
    }
}

編寫service層程式碼,這個功能的核心邏輯都在service方法中

@Service
public class ParamParseService {

    public void parseJar(ParamParseDTO paramParseDTO) {
        // 1 將上傳的jar檔案儲存到本地
        File file = new File(getWorkspacePath(paramParseDTO.getPath()),paramParseDTO.getJarName());
        try(FileOutputStream outputStream = new FileOutputStream(file)){
            outputStream.write(paramParseDTO.getJar());
        }catch (Exception e){
            e.printStackTrace();
        }
        // 現場保護
        ClassLoader current = Thread.currentThread().getContextClassLoader();
        try {
            // 2 獲取本地檔案的classLoader
            ClassLoader jarClassLoader = getClassLoader(new File[] {file});
            // 3 進行反射解析
            Thread.currentThread().setContextClassLoader(jarClassLoader);
            // 4 使用指定的類載入器 獲取上傳jar包中的指定類的class物件
            Class<?> aClass = Class.forName(paramParseDTO.getService(), true,Thread.currentThread().getContextClassLoader());

            Object obj = aClass.newInstance();
            System.out.println(obj.hashCode());
        }catch (Exception e){
            e.printStackTrace();
        }
        // 恢復現場
        Thread.currentThread().setContextClassLoader(current);
    }

    public static String getWorkspacePath(String path) {
        File dir = new File(System.getProperty("user.dir"), "automation"+File.separator+path);
        try {
            FileUtils.forceMkdir(dir);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return dir.getAbsolutePath();
    }


    public ClassLoader getClassLoader(File[] jars) throws IOException {
        ArrayList<URL> classpath = new ArrayList<>();
        if (jars != null && jars.length > 0) {
            for (File jar : jars) {
                classpath.add(jar.toURI().toURL());
            }
        }

        return new URLClassLoader(classpath.toArray(new URL[0]), Thread.currentThread().getContextClassLoader());
    }
}

   這篇文字只是記錄了主要的流程,至於業務就是在這個基礎上進行擴充套件的

 

參考連結:

https://shixin.blog.csdn.net/article/details/54604224

 

 

相關文章