为什么没有为Jersey控制器检测到我的Aspect(使用自定义注释)?

时间:2014-01-21 23:51:28

标签: java jersey aop aspectj spring-aop

我想在Jersey控制器上创建一个Aspect来衡量服务执行的时间。我正在与我的切入点作斗争,因为它没有被检测到,我的方面永远不会被启动。

我尝试过使用许多切入点,例如:

execution(@Monitor * *.*(..))
execution(public * *(..))
change the order of @Aspect and @Component

Added a pointcut like this:
@Pointcut("execution(@Monitor * *.*(..))")
public void monitorRequestTargets(){}
@Around("monitorRequestTargets()")

Tried using AOP and CGLIB
<aop:aspectj-autoproxy proxy-target-class="true"/>

Also tried changing the order of configuration in context.xml

Eclipse检测到我的方法正在建议我的方法,但它不会在运行时执行。你能否给我一些提示,说明为什么没有创建方面或切入点没有启动?

我的代码如下。

context.xml中

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <!-- Enables the Spring MVC @Controller -->
    <annotation-driven />

    <!-- Enables AspectJ -->
    <aop:aspectj-autoproxy />

    <!-- .....more definitions -->

    <context:component-scan base-package="com.mypackage" />

</beans:beans>

我的 MonitorAspect

@Component
@Aspect
public class MonitorAspect
{
    private static final Logger logger = LoggerFactory.getLogger(MonitorAspect.class);

    @Around("@annotation(com.mypackage.Monitor)")
    public void logTimeUsage(ProceedingJoinPoint joinPoint) throws Throwable 
    {
        // Store executing method
        String method = joinPoint.getSignature().getName();

        // Track time
        long startTime = System.currentTimeMillis();
        joinPoint.proceed();
        long endTime = System.currentTimeMillis();

        long duration = endTime - startTime;

        // Log time consumed by executing method
        logger.info(method + ": " + duration);

    }
}

My Monitor自定义注释

@Target(value = {ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Monitor
{

}

我想使用方面的控制器:

    @Monitor
    @POST
    @Consumes("application/json")
    @Produces("application/json")
    @Path("/{tkn}/test/")
    public Response test(
            @Context HttpServletRequest httpReq,
            @Context UriInfo uri,
                     String enrollReqJson
            ) {
          Thread.sleep(1000); // Implementation is not important
    }

我的 pom.xml

<!-- Spring -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>${org.springframework-version}</version>
    <exclusions>
        <!-- Exclude Commons Logging in favor of SLF4j -->
        <exclusion>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
        </exclusion>
    </exclusions>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>${org.springframework-version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-tx</artifactId>
    <version>${org.springframework-version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>${org.springframework-version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-orm</artifactId>
    <version>${org.springframework-version}</version>
</dependency>
  <!-- Jersey / Spring -->
<dependency>
    <groupId>com.sun.jersey.contribs</groupId>
    <artifactId>jersey-spring</artifactId>
    <version>1.14</version>
    <exclusions>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </exclusion>
        <exclusion>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-bundle</artifactId>
    <version>1.8</version>
</dependency>
        <dependency>
    <groupId>com.sun.jersey.contribs</groupId>
    <artifactId>jersey-multipart</artifactId>
    <version>1.8</version>
</dependency>
        <!-- Spring AOP / AspectJ -->
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjrt</artifactId>
    <version>${org.aspectj-version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${org.springframework-version}</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>${org.aspectj-version}</version>
</dependency>

2 个答案:

答案 0 :(得分:3)

看起来我遇到了同样的问题。根据您提供的内容,看起来您在Spring上创建的对象上使用Spring AOP(可能是Jersey是创建控制器类实例的对象),因此建议未应用。 Eclipse说它被建议,但这只适用于由Spring创建的控制器实例。您实际使用的是Jersey(或您正在使用的任何提供商)创建的那些,不建议使用。

我花了很多时间试图让Jersey使用Spring来创建控制器实例(包括一些声称能够做到这一点的插件),但从来没有让它工作。我能够直接使用AspectJ而不是Spring AOP来实现它。这不是很难,除了弄清楚如何让春天注入这个方面。

添加了:

注释保持不变。您只需要从spring.xml中删除AOP内容,并在META-INF中创建一个aop.xml文件。这就是我的样子:

<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
    <aspects>
        <aspect name="com.ancestry.academy.api.ServiceApiAspect" />
        <aspect name="com.ancestry.academy.manager.ManagerApiAspect" />
    </aspects>
</aspectj>

您可以将Spring AOP保留为弹簧加载的类。您只需要为在spring之外创建的类(如jax的控制器)执行此操作。

我真的不懂一点黑魔法。如果你需要使用spring注入你自己的方面,那么你需要在spring.xml中声明它,如下所示:

<bean id="serviceApiAspect" class="com.ancestry.academy.api.ServiceApiAspect" factory-method="aspectOf" />

<bean id="managerApiAspect" class="com.ancestry.academy.manager.ManagerApiAspect" factory-method="aspectOf" />

请注意,我的方面没有名为aspectOf的方法。显然是由AspectJ添加的。这就是它的全部内容。

答案 1 :(得分:0)

添加

compile 'org.aspectj:aspectjtools:1.8.1'
compile 'org.aspectj:aspectjrt:1.8.1'

制作注释

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ParmsAudit
{
  String action();
}

方面类

@Aspect
public class AuditAspect {

@Before(value="execution(@uk.co.billcomer.audit.ParmsAudit * *(..)) &&   @annotation(parmsAudit)", argNames="parmsAudit")
public void logTheAuditActivity(JoinPoint aPoint, ParmsAudit parmsAudit) {
 String userName = getUserName();
 mlogger.info("Parms Auditing User Name: " + userName);
 mlogger.info("auditType:" + parmsAudit.auditType().getDescription());

 String arguments = getArgs(aPoint.getArgs());

 if (arguments.length() > 0) {
 mlogger.info("args-" + arguments);
 }
}

private String getArgs(Object[] args) {
 String arguments = "";
 int argCount = 0;

 for (Object object : args) {
   if (argCount > 0) {
     arguments += ", ";
   }
   arguments += "arg[" + ++argCount + "]=" + "[" + object + "]";
 }
 return arguments;
}

private String getUserName() {
 try {
   return SecurityContextHolder.getContext().getAuthentication().getName();
 } catch (NullPointerException npe) {
   return "Unknown User";
 }
}
}

这是很好的链接http://billcomer.blogspot.in/2011/07/auditing-using-aop-and-annotations-in.html