Вероятно, что аспект перехватывает вызов нестатического метода обслуживания.
Есть несколько способов профилировать выполнение и найти горячую точку для вашего вызова службы. Для репликации этой проблемы я использовал тестовый профилировщик NetBeans.
Сначала я создал статические (компонентные) и нестатические службы:
@Service
public class DemoService {
private static final ConcurrentMap<Integer, String> CACHE = new ConcurrentHashMap<>();
public DemoService() {
for (int i = 0; i < 128; i++) {
CACHE.put(i, String.valueOf(i));
}
}
public String queryByIdFromCache(Integer id) {
return CACHE.getOrDefault(id, "");
}
}
public class DemoStaticService {
private static final ConcurrentMap<Integer, String> CACHE = new ConcurrentHashMap<>();
static {
for (int i = 0; i < 128; i++) {
CACHE.put(i, String.valueOf(i));
}
}
public static String queryByIdFromCache(Integer id) {
return CACHE.getOrDefault(id, "");
}
}
Затем я создал контроллер с двумя действиями, одно из которых вызывает нестатический, внедренный сервис, а другое - сервис, использующий статический метод:
@RestController
@RequestMapping(path = "/demo")
public class DemoController {
@Autowired
private DemoService demoService;
@GetMapping(path = "/demo")
public String callService(@RequestParam Integer id) {
return demoService.queryByIdFromCache(id);
}
@GetMapping(path = "/static-demo")
public String callStaticService(@RequestParam Integer id) {
return DemoStaticService.queryByIdFromCache(id);
}
}
После этого я написал два модульных теста, чтобы помочь мне с профилированием методов обслуживания:
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoControllerTest {
@Autowired
private DemoController demoController;
@Before
public void before() {
demoController.callService(1);
demoController.callStaticService(1);
}
@Test
public void testCallService() {
for (int id = 0; id < 128; id++) {
demoController.callService(id);
}
}
@Test
public void testCallStaticService() {
for (int id = 0; id < 128; id++) {
demoController.callStaticService(id);
}
}
}
Когда тестовый файл был открыт, я выбрал пункт меню Profile -> Profile Test File
:
Затем из выпадающего списка ▶ Profile
я выбрал вариант Methods
:
Наконец я нажал кнопку ▶ Profile
, чтобы профилировать тесты. Я получил такой результат, который показывает, что вызов внедренного сервиса только на 50% дороже, чем вызов статического метода:
Но что, если второй метод был перехвачен аспектом (например, @Transactional
)?
Чтобы проверить это, я обновил DemoService
и сделал его метод транзакционным
@Service
public class DemoService {
private static final ConcurrentMap<Integer, String> CACHE = new ConcurrentHashMap<>();
public DemoService() {
for (int i = 0; i < 128; i++) {
CACHE.put(i, String.valueOf(i));
}
}
@Transactional
public String queryByIdFromCache(Integer id) {
return CACHE.getOrDefault(id, "");
}
}
После повторного запуска тестов я получил этот результат профилирования на этот раз:
Как видно, транзакционный аспект сделал вызов в DemoService.queryByIdFromCache
примерно в 14,5 (10,2 / 0,708) раз медленнее.
Чтобы найти основную причину замедления в вашем методе обслуживания, я предлагаю вам настроить аналогичный тест и профилировать его с помощью NetBeans Profiler (или чего-то подобного).