fragments

Jul 02, 2022

使用Javac日志分析工程依赖

Last updated at: Jul 02, 2022

最近的工作是迁移一个历史遗留的工件(本文称之为工件A),首先需要梳理这个工件的消费者。初步计划按照下面步骤进行:

  1. 在代码搜索引擎(例如zoekt)里搜索:
    • 关键词:工件A的java文件头部的import包名
    • 文件类型:java 然后将所有结果的工程名进行排重,得到工件A的所有消费者工程。

    Q:为什么不能直接搜索pom.xml文件中搜索工件A的名称呢?

    A:因为存在工件A的消费者工件传递依赖工件A的情况,此种方法不能覆盖传递依赖的场景🥹

  2. 使用Intellij IDEA打开每个消费者工程,依次查看工件A中的服务接口(interface)的使用,菜单Navigatie>Declaration or Usages
  3. 记录工件A的服务接口存在被使用的方法(后续实现对应的替换接口)

🤨不过看第2、3个步骤看起来挺花时间的,还有其他办法吗?

目前想到的其他办法就是从编译器日志下手,查得可以使用-verbose选项,来实现:

Uses verbose output, which includes information about each class loaded and each source file compiled.

下面通过一个demo来演示:

  1. 使用maven创建工件A:

    ➜ mvn archetype:generate \
            -DarchetypeGroupId=org.apache.maven.archetypes \
            -DarchetypeArtifactId=maven-archetype-quickstart \
            -DarchetypeVersion=RELEASE \
            -DgroupId=demo.a \
            -DartifactId=demo-a \
            -Dversion=0.0.1-SNAPSHOT \
            -DinteractiveMode=false
    

    然后添加dto、service类:

    ➜ tree src/main/java/
    src/main/java/
    └── demo
        └── a
            ├── dto
            │   ├── ProductDto.java
            │   └── StockDto.java
            └── service
                ├── IProductService.java
                └── impl
                    └── ProductServiceImpl.java
    
    5 directories, 4 files
    

    install 到本地仓库:

    ➜ mvn install
    
  2. 使用maven创建消费者工件:

    ➜ mvn archetype:generate \
            -DarchetypeGroupId=org.apache.maven.archetypes \
            -DarchetypeArtifactId=maven-archetype-quickstart \
            -DarchetypeVersion=RELEASE \
            -DgroupId=demo.consumer \
            -DartifactId=demo-consumer \
            -Dversion=0.0.1-SNAPSHOT \
            -DinteractiveMode=false
    

    在pom.xml添加工件A的依赖

    <dependency>
      <groupId>demo</groupId>
      <artifactId>demo-a</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    </dependency>
    

    在App类main方法使用demo.a.service.IProductService

    package demo.consumer;
    
    import demo.a.dto.ProductDto;
    import demo.a.service.IProductService;
    import demo.a.service.impl.ProductServiceImpl;
    
    /**
    * Hello world!
    */
    public class App {
        public static void main(String[] args) {
            final IProductService productService = new ProductServiceImpl();
            final ProductDto productDto = productService.getProductById("1"); // 注意点1
            System.out.println(productDto.price);
        }
    }
    

    在pom.xml的maven-compiler-plugin配置javac参数-verbose

    <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.0</version>
        <configuration>
        <compilerArgs>
            <arg>-verbose</arg>
        </compilerArgs>
        </configuration>
    </plugin>
    

    构建并且将javac日志重定向到文件javac.log

    ➜ mvn clean compile 2>javac.log
    
  3. 查看文件javac.log,不难发现使用到的服务接口类及dto类都在日志中:

    ➜ grep -nF /demo/a/ javac.log 
    5:[loading /Users/zenuo/.m2/repository/demo/demo-a/0.0.1-SNAPSHOT/demo-a-0.0.1-SNAPSHOT.jar(/demo/a/dto/ProductDto.class)]
    6:[loading /Users/zenuo/.m2/repository/demo/demo-a/0.0.1-SNAPSHOT/demo-a-0.0.1-SNAPSHOT.jar(/demo/a/service/IProductService.class)]
    7:[loading /Users/zenuo/.m2/repository/demo/demo-a/0.0.1-SNAPSHOT/demo-a-0.0.1-SNAPSHOT.jar(/demo/a/service/impl/ProductServiceImpl.class)]
    

🧐回到java代码中的注意点1:这种写法显式import了demo.a.dto.ProductDto,若换成不显式import的写法,日志中是否仍然存在demo.a.dto.ProductDto呢?现在将代码改为如下:

package demo.consumer;

import demo.a.service.IProductService;
import demo.a.service.impl.ProductServiceImpl;

/**
 * Hello world!
 */
public class App {
    public static void main(String[] args) {
        final IProductService productService = new ProductServiceImpl();
        System.out.println(productService.getProductById("1").price);
    }
}

构建并且将javac日志重定向到文件javac.log.1

➜ mvn clean compile 2>javac.log.1

查看javac.log.1,是仍然存在的,只是位置不同:

➜ grep -nF /demo/a/ javac.log.1  
5:[loading /Users/zenuo/.m2/repository/demo/demo-a/0.0.1-SNAPSHOT/demo-a-0.0.1-SNAPSHOT.jar(/demo/a/service/IProductService.class)]
6:[loading /Users/zenuo/.m2/repository/demo/demo-a/0.0.1-SNAPSHOT/demo-a-0.0.1-SNAPSHOT.jar(/demo/a/service/impl/ProductServiceImpl.class)]
17:[loading /Users/zenuo/.m2/repository/demo/demo-a/0.0.1-SNAPSHOT/demo-a-0.0.1-SNAPSHOT.jar(/demo/a/dto/ProductDto.class)]

实例代码demo.zip

参考

(248 words)