SpringBoot自定義maven-plugin插件整合asm代碼插樁
背景
公司開發框架增加瞭web系統license授權證書校驗模塊,實行一臺機器一個授權證書,初步方案是增加攔截器針對全局請求進行攔截校驗,評估後認為校驗方式單一,應該增加重要工具類,業務service實現中每個方法的進行校驗,因為涉及代碼量較大硬編碼工作困難,故選擇通過自定義maven插件在編譯期間進行動態代碼插樁操作
項目配置
新建maven項目設置打包方式
<packaging>maven-plugin</packaging>
增加依賴項
<!--使用doc的方式--> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-plugin-api</artifactId> <version>3.5.2</version> </dependency> <!--使用註解的方式--> <dependency> <groupId>org.apache.maven.plugin-tools</groupId> <artifactId>maven-plugin-annotations</artifactId> <version>3.5.2</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-project</artifactId> <version>2.2.1</version> </dependency> <dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>9.0</version> </dependency>
build內容配置
<plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-plugin-plugin</artifactId> <version>3.5</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.6.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins>
編譯攔截
創建編譯操作類FramePlugin,繼承AbstractMojo並使用Mojo註解標註,output參數是class文件編譯後路徑
@Mojo(name = "deepcompile", defaultPhase = LifecyclePhase.COMPILE) public class FramePlugin extends AbstractMojo { @Parameter(name = "output", defaultValue = "${project.build.directory}") private File output; public void execute() throws MojoExecutionException { File f = ; if (!f.exists()) { f.mkdirs(); } try { insertPile(f); } catch (Exception e) { exceptioncount++; e.printStackTrace(); } }
ASM插樁
新建ClassVisitor重寫visitMethod方法來過濾訪問需要插樁的方法,需要排除自帶的init方法
public class MethodCoverageClassVisitor extends ClassVisitor { public MethodCoverageClassVisitor(ClassVisitor classVisitor) { super(Opcodes.ASM9, classVisitor); } @Override public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { final MethodVisitor methodVisitor = super.visitMethod(access, name, descriptor, signature, exceptions); if (name.equals("<init>")) { return methodVisitor; } return new MethodCoverageMethodVisitor(Opcodes.ASM9, methodVisitor); } }
新建MethodVisitor重寫visitCode方法針對方法內部字節碼進行自定義操作,這裡是使用框架內部封裝好的一個靜態方法來校驗license證書
public class MethodCoverageMethodVisitor extends MethodVisitor { public MethodCoverageMethodVisitor(int api, MethodVisitor methodVisitor) { super(api, methodVisitor); } @Override public void visitCode() { mv.visitFieldInsn(Opcodes.INVOKESTATIC, "com/xxxx/frame/common/utils/ComplieSDK", "checkLicense", "()V"); } }
最後在execute中進行文件遞歸查找調用,就是將已經編譯的class文件讀取/自定義操作後保存
private void insertPile(File root) throws IOException { if (root.isDirectory()) { for (File file : root.listFiles()) { insertPile(file); } } String className = root.getName().replace(".class", ""); if (root.getName().endsWith(".class")) { //class篩選 boolean flag = false; //自定義的class文件篩選條件代碼 if (flag) { System.out.println("【insertPile】:" + className); FileOutputStream fos = null; try { final byte[] instrumentBytes = doInsertPile(root); fos = new FileOutputStream(root); fos.write(instrumentBytes); fos.flush(); } catch (MojoExecutionException e) { System.out.println("【insertPile-exception】:" + className); e.printStackTrace(); } finally { if (fos != null) { fos.close(); } } } } }
項目使用
maven-plugin項目執行mvn install安裝到本地倉庫
框架項目配置自定義maven插件進行打包,配置執行的聲明周期為complie(編譯),這裡goal自定義命令名稱需要和mojo註解標註類中指定的name名稱一致
<plugin> <groupId>com.xxxxx</groupId> <artifactId>frame-maven-plugin</artifactId> <version>1.2.5</version> <executions> <execution> <goals> <!-- 執行目標 --> <goal>deepcompile</goal> </goals> <!-- 執行這個目標所在的生命周期 --> <phase>compile</phase> </execution> </executions> </plugin>
到此這篇關於SpringBoot自定義maven-plugin插件整合asm代碼插樁的文章就介紹到這瞭,更多相關maven-plugin asm代碼插樁內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Maven引用自定義jar包方式
- maven-compiler-plugin版本指定方式
- maven工程中jar包瘦身的五種方法
- 使用maven war包打包去除jar包瘦身
- 解決import包時報 Java 程序包不存在的問題