12

我有一个使用 CXF 在 Java 中实现的工作 SOAP Web 服务。在服务器端计算方法执行的好方法是什么?

我现在所做的是使用拦截器。我已经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");
    }

有一个更好的方法吗?我正在阅读有关通过代理执行方法的信息,但我不知道该怎么做。

问题更新:

我用谷歌搜索了更多使用代理的第二种方式,即:

@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;
         }
    }

根据到目前为止对这个问题的评论,使用拦截器比使用代理更好。我希望尽可能减慢 Web 服务的速度(这肯定会减慢速度),同时获得精确的性能测量。

4

4 回答 4

10

我不推荐您使用 InInterceptor 和 OutInterceptor 的第一种方法 - 原因是没有干净的方法来存储 starttime - 您有令牌将其存储在静态变量中的方法在线程环境中不起作用。

您使用 AOP 的第二种方法非常好,但是它不会给出在 CXF 堆栈中花费的时间,它只会在调用到达您的服务层时提供时间。

我觉得最好的方法是使用 servlet 过滤器,你可以这样做:

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.");
}

并在您为 CXFServlet 提供映射的同一 uri 中提供映射。

这应该更清洁。如果您想要更精细的东西,您可以将这种方法与您的 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>
于 2012-05-10T22:12:56.473 回答
5

根据马特的回答,我得出以下结论。关键是在 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");
        }
    }       
}
于 2013-03-24T12:18:47.240 回答
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.cxfor开头javax.xml.ws,因此您可以通过使用其中一个拦截器的完全限定类名来使映射键唯一。

于 2012-05-11T16:02:29.327 回答
0

计算服务器端的方法执行?

使用Interceptors你也在测量CXF
我的意思Interceptors是用于预先/后处理与您的应用程序逻辑相关的消息。
使用Interceptor您的测量包括 CXF 流量链的一部分。
如果这是你想要的,那么好的。
但是如果你想测量你的方法执行,你应该把时间间隔与你的方法联系起来。

于 2012-05-11T19:17:19.923 回答