我需要统计特定包下的任何方法被调用了多少次(类似于Hieracy,但在运行时,导出结果)
例如: 方法setA被调用17次,方法setB被调用3次...
基于this答案我成功提取了实现类中的所有方法,但我不知道如何找到生产代码中的所有用途。
public static List<Class<?>> find(String scannedPackage) {
String scannedPath = scannedPackage.replace(PKG_SEPARATOR, DIR_SEPARATOR);
URL scannedUrl = Thread.currentThread().getContextClassLoader().getResource(scannedPath);
if (scannedUrl == null) {
throw new IllegalArgumentException(String.format(BAD_PACKAGE_ERROR, scannedPath, scannedPackage));
}
File scannedDir = new File(scannedUrl.getFile());
List<Class<?>> classes = new ArrayList<Class<?>>();
for (File file : scannedDir.listFiles()) {
classes.addAll(find(file, scannedPackage));
}
return classes;
}
private static List<Class<?>> find(File file, String scannedPackage) {
List<Class<?>> classes = new ArrayList<Class<?>>();
String resource = scannedPackage + PKG_SEPARATOR + file.getName();
if (file.isDirectory()) {
for (File child : file.listFiles()) {
classes.addAll(find(child, resource));
}
} else if (resource.endsWith(CLASS_FILE_SUFFIX)) {
int endIndex = resource.length() - CLASS_FILE_SUFFIX.length();
String className = resource.substring(0, endIndex);
if (className.endsWith("ActivityImpl")) {
try {
classes.add(Class.forName(className));
} catch (ClassNotFoundException ignore) {
}
}
}
return classes;
}
并像这样使用它:
public static void main(String[] args) throws Exception {
List<Class<?>> classes = find("com.my.project.activities");
for (Class c : classes) {
System.out.println("Class name: " + c.getName());
System.out.print("Methods: ");
Method[] methods = c.getDeclaredMethods();
for (Method method : methods) {
System.out.print(method.getName() + ", ");
}
System.out.println();
System.out.println();
}
}
如何统计每种方法的使用次数?
更多信息:Java 21、Spring Boot 3.2.4
计算方法调用次数的最佳方法是使用方面。请参阅https://docs.spring.io/spring-framework/docs/4.3.15.RELEASE/spring-framework-reference/html/aop.html 面向方面的编程一开始似乎很难,但它给了你行动上的自由,更重要的是,它会让你的方法保持完整。这是一个简短的例子: 首先我们必须包含依赖项 如果我们使用 gradle 它将位于文件 build.gradle 中
implementation ('org.springframework.boot:spring-boot-starter-aop')
如果使用maven,则在maven.xml中包含模拟 我们将编写一个带有测试方法的类
@Component
public class ClassWithMethods {
// method under consideration
public void setA() {
}
public void setB() {
}
}
看,我们不会改变这个类来进行方法调用计数。 然后我们写aspect
@Aspect
@Component // this aspect will be a spring bean
public class AspectForCountingMethodCalls {
public static AtomicLong setACounter = new AtomicLong(0L);
public static AtomicLong setBCounter = new AtomicLong(0L);
@Before("execution (* setA(..))") // executed before every call setA
public void countSetACall() {
setACounter.getAndIncrement(); // increase counter
}
@Before("execution (* setB(..))") // executed before every call setB
public void countSetBCall() {
setBCounter.getAndIncrement(); // increase counter
}
}
现在我们可以测试并享受它了
@SpringBootTest
public class AspectTest {
@Autowired
ClassWithMethods classWithMethods;
@Test
void testCounter() {
// call setA 10 times
for (int i = 0; i < 10; i++) {
classWithMethods.setA();
}
// call setB 10 times
for (int i = 0; i < 100; i++) {
classWithMethods.setB();
}
// verify that our aspect works
assertEquals(10L, AspectForCountingMethodCalls.setACounter.get());
assertEquals(100L, AspectForCountingMethodCalls.setBCounter.get());
}
}
我们可以用方面做更多的事情,但这超出了这个答案的范围