Мне нужно подсчитать, сколько раз вызывается какой-либо метод в конкретном пакете (аналогично Hieracy, но во время выполнения, чтобы экспортировать результаты).
Например: Метод setA вызывается 17 раз, метод setB вызывается 3 раза...
Основываясь на этом ответе, мне удалось извлечь все методы из классов реализации, но я не знаю, как найти все варианты их использования в рабочем коде.
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.xml, если используется maven. Напишем класс с методами для тестирования
@Component
public class ClassWithMethods {
// method under consideration
public void setA() {
}
public void setB() {
}
}
Посмотрите, мы не будем менять этот класс для подсчета вызовов методов. Затем пишем аспект
@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 17 times
for (int i = 0; i < 17; i++) {
classWithMethods.setA();
}
// call setB 3 times
for (int i = 0; i < 3; i++) {
classWithMethods.setB();
}
// verify that our aspect works
assertEquals(17L, AspectForCountingMethodCalls.setACounter.get());
assertEquals(3L, AspectForCountingMethodCalls.setBCounter.get());
}
}
Мы можем сделать гораздо больше с аспектами, но это выходит за рамки этого ответа.
Это может быть хорошей идеей, я могу использовать AOP и запускать потоки E2E... Спасибо.
Похоже, вам нужен профайлер