Подтвердить что ты не робот

Расчет времени выполнения запроса веб-сервиса

У меня есть рабочий веб-сервис 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;
         }
    }

На основе комментариев к этому вопросу до сих пор использование перехватчиков лучше, чем использование прокси. Я хочу как можно меньше замедлить веб-сервис (это, безусловно, замедлит его), и в то же время получить точное измерение производительности.

4b9b3361

Ответ 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.
Если это то, что вы хотите, тогда хорошо. Но если вы хотите измерить выполнение вашего метода, вы должны поместить интервал времени в соответствие с вашим методом.