Расчет времени выполнения запроса веб-сервиса
У меня есть рабочий веб-сервис SOAP, реализованный с CXF в Java. Что было бы хорошим способом вычислить выполнение метода на стороне сервера?
То, что я сделал сейчас, я использовал перехватчики. Я определил public static long start
в моем InInterceptor (Phase.RECEIVE). И в моем OutInterceptor (Phase.SEND) я вычисляю время отклика следующим образом:
@Override
public void handleMessage(Message arg0) {
long stop = System.currentTimeMillis();
long executionTime = stop - RequestStartInterceptor.start;
System.out.println("execution time was ~" + executionTime + " ms");
}
Есть ли лучший способ сделать это? Я читал о выполнении метода прокси-сервера, но я не знаю, как это сделать.
Обновление вопроса:
Я немного искал поисковую систему, используя второй прокси-сервер i.e:
@Aspect
public class MyServiceProfiler {
@Pointcut("execution(* gov.noaa.nhc.*.*(..))")
public void myServiceMethods() { }
@Around("myServiceMethods()")
public Object profile(ProceedingJoinPoint pjp) throws Throwable {
long start = System.currentTimeMillis();
System.out.println("Going to call the method.");
Object output = pjp.proceed();
System.out.println("Method execution completed.");
long elapsedTime = System.currentTimeMillis() - start;
System.out.println("Method execution time: " + elapsedTime + " milliseconds.");
return output;
}
}
На основе комментариев к этому вопросу до сих пор использование перехватчиков лучше, чем использование прокси. Я хочу как можно меньше замедлить веб-сервис (это, безусловно, замедлит его), и в то же время получить точное измерение производительности.
Ответы
Ответ 1
Я бы не рекомендовал ваш первый подход к использованию InInterceptor и OutInterceptor - причина в том, что нет чистого способа сохранить время начала - подход, который у вас есть, чтобы хранить его в статической переменной, не будет работать в потоковой среде.
Ваш второй подход к использованию AOP очень хорош, однако он не даст времени, потраченного в стеке CXF, он предоставит вам только время, когда вызов достигнет вашего уровня обслуживания.
Я считаю, что лучший подход будет использовать фильтр сервлета, вы можете сделать это:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
long start = System.currentTimeMillis();
chain.doFilter(request, response);
long elapsedTime = System.currentTimeMillis() - start;
System.out.println("Method execution time: " + elapsedTime + " milliseconds.");
}
и предоставить отображение в том же uri, где вы предоставили сопоставление для CXFServlet.
Это должно быть намного более чистым. Если вам нужно что-то еще более гранулированное, вы можете смешать этот подход с вашим методом AOP, чтобы найти общее время отклика, а затем разбить его на время отдельных методов обслуживания.
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/webservices/*</url-pattern>
</servlet-mapping>
<filter-mapping>
<filter-name>ExecTimeFilter</filter-name>
<url-pattern>/webservices/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
Ответ 2
Основываясь на ответе матов, я разработал следующее. Ключ в том, что в OutgoingInterceptor вам нужно получить входящее сообщение и получить от него временную метку.
public class IncomingInterceptor extends AbstractPhaseInterceptor<Message> {
public IncomingInterceptor() {
super(Phase.RECEIVE);
}
@Override
public void handleMessage(Message msg) throws Fault {
long startTime = System.currentTimeMillis();
msg.put("my.timing.start", startTime);
}
}
public class OutgoingInterceptor extends AbstractPhaseInterceptor<Message> {
Logger log = LoggerFactory.getLogger(AbstractPhaseInterceptor.class);
public OutgoingInterceptor() {
super(Phase.SEND);
}
@Override
public void handleMessage(Message msg) throws Fault {
Long startTime = (Long)msg.getExchange().getInMessage().remove("my.timing.start");
if (startTime != null) {
long executionTime = System.currentTimeMillis() - startTime;
log.info("execution time was ~" + executionTime + " ms");
} else {
log.info("timer not found");
}
}
}
Ответ 3
Я думаю, что перехватчики могут помещать произвольные данные в объект Message
, поэтому вы можете сохранить время начала там, а затем вернуть его обратно, чтобы вычислить время, прошедшее.
// in your receive interceptor
@Override
public void handleMessage(Message message) {
long startTime = System.currentTimeMillis();
message.put("my.timing.start", startTime);
}
.
// in your send interceptor
@Override
public void handleMessage(Message message) {
Long startTime = message.remove("my.timing.start");
if (startTime != null) {
long executionTime = System.currentTimeMillis() - startTime;
System.out.println("execution time was ~" + executionTime + " ms");
}
}
CXF сохраняет некоторые свои данные на карте сообщений, но большинство его ключей начинаются с org.apache.cxf
или javax.xml.ws
, поэтому вы можете просто сделать свой ключ карты уникальным, используя полное имя класса одного из ваши перехватчики.
Ответ 4
вычислить выполнение метода на стороне сервера?
Используя Interceptors
, вы также измеряете CXF
!
Я имею в виду, что Interceptors
используется для предварительного/пост-обработки сообщения в отношении вашей логики приложения.
Используя Interceptor
, ваши измерения включают части цепи потока CXF.
Если это то, что вы хотите, тогда хорошо.
Но если вы хотите измерить выполнение вашего метода, вы должны поместить интервал времени в соответствие с вашим методом.