2015-03-13 115 views
1

我开发了一个不错的Spring Aspect,我可以使用它来监视我的服务操作性能。如果某些操作需要很长时间才能执行,则会记录它们。根据环境变量或属性执行PointCut

@Aspect 
public class PerformanceMonitorAspect { 

    private Logger logger = LoggerFactory.getLogger("performance"); 

    @Pointcut("execution(* com.company.MyService+.*(..))") 
    public void pointCut(){ 

    } 

    @Around("pointCut()") 
    public Object profileServiceMethods(ProceedingJoinPoint thisJoinPoint) throws Throwable { 
     MethodSignature ms = (MethodSignature) thisJoinPoint.getSignature(); 
     Method m = ms.getMethod(); 
     long t1 = System.nanoTime(); 
     Object result = thisJoinPoint.proceed(); 
     long t2 = System.nanoTime(); 
     long millis = TimeUnit.NANOSECONDS.toMillis(t2 - t1); 
     if (millis < 1000) { 
      logger.trace("Execution time for {}: {} ms", m.getName(), millis); 
     } else { 
      logger.warn("Substantial execution time for {}: {} ms", m.getName(), 
        millis); 
     } 
     return result; 
    } 

} 

然而,因为它是一个@Around建议,春季需要以轮廓他们我所有的方法调用的控制。调试时这有点不舒服(它甚至会误导Eclipse本身),所以我希望仅当我的应用程序处于生产阶段时才执行Pointcut。我可以将Pointcut配置为根据环境变量,Java属性或类似条件有条件地执行吗?

Documentation只能引用方法变量条件......在此先感谢!

编辑

正如@ DavidL的建议下,我改变了我的切入点,以这样的:

@Pointcut("execution(* com.tadic.module.TadicModuleGeneric+.*(..)) && if()") 
public static boolean pointCut() { 
    return true; 
} 

这是Eclipse不警告什么的方式。然而,我在运行时得到这个:

GRAVE: Critical error during deployment: 
java.lang.VerifyError: Expecting a stackmap frame at branch target 7 
Exception Details: 
    Location: 
    com/mycompany/aspects/AuditAspect.<clinit>()V @1: invokestatic 
    Reason: 
    Expected stackmap frame at this location. 
    Bytecode: 
    0000000: 00b8 0134 a700 084b 2ab3 012f b1  
    Exception Handler Table: 
    bci [1, 7] => handler: 7 

    at java.lang.Class.getDeclaredMethods0(Native Method) 
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2615) 
    at java.lang.Class.getDeclaredMethods(Class.java:1860) 
    at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:474) 
    at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:458) 
    at org.springframework.util.ReflectionUtils.getUniqueDeclaredMethods(ReflectionUtils.java:518) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryMethod(AbstractAutowireCapableBeanFactory.java:639) 
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:575) 
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1350) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:355) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:326) 
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:434) 
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:624) 
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:461) 
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:410) 
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306) 
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112) 
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4973) 
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5467) 
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) 
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559) 
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549) 
    at java.util.concurrent.FutureTask.run(FutureTask.java:262) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) 
    at java.lang.Thread.run(Thread.java:745) 

所以看起来织布工没有做得好。有什么建议么?

编辑2 当我通过基于Spring AOP代理的方面使用AspectJ时,会发生此问题。我使用Maven构建项目,并使用Eclipse AspectJ插件将其集成到我的工作区中。 AspectJ版本是1.8.2,Spring-AOP版本是3.2.8.RELEASE,我正在用Java 7.0.75 JDK构建它。

这是正在使用的POM的样品:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 
    <modelVersion>4.0.0</modelVersion> 

    <groupId>com.tesicnor.test</groupId> 
    <artifactId>aspect-test</artifactId> 
    <version>0.0.1-SNAPSHOT</version> 
    <packaging>jar</packaging> 

    <name>aspect-test</name> 
    <url>http://maven.apache.org</url> 

    <properties> 
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 
     <maven.compiler.source>1.7</maven.compiler.source> 
     <maven.compiler.target>1.7</maven.compiler.target> 
     <aspectj.version>1.8.2</aspectj.version> 
    </properties> 

    <build> 
     <plugins> 
      <plugin> 
       <groupId>org.codehaus.mojo</groupId> 
       <artifactId>aspectj-maven-plugin</artifactId> 
       <version>1.7</version> 
       <configuration> 
        <complianceLevel>1.7</complianceLevel> 
        <source>1.7</source> 
        <target>1.7</target> 
       </configuration> 
       <executions> 
        <execution> 
         <goals> 
          <goal>compile</goal> 
         </goals> 
        </execution> 
       </executions> 
      </plugin> 
     </plugins> 
    </build> 

    <dependencies> 
     <dependency> 
      <groupId>org.aspectj</groupId> 
      <artifactId>aspectjrt</artifactId> 
      <version>${aspectj.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>org.aspectj</groupId> 
      <artifactId>aspectjweaver</artifactId> 
      <version>${aspectj.version}</version> 
     </dependency> 
     <dependency> 
      <groupId>org.springframework</groupId> 
      <artifactId>spring-aop</artifactId> 
      <version>3.2.8.RELEASE</version> 
     </dependency> 
    </dependencies> 


</project> 

这POM是一个给我创建了一个功能性的测试用例。我目前的项目是巨大的,似乎还有其他依赖造成麻烦。

+0

曾经有导致堆栈跟踪几个错误就像您在早期版本的AspectJ 1.8中关于Java 8一样。您能否告诉我您使用的是哪一种Java和AspectJ版本?你如何建立? Maven的?如果是这样,请显示POM。您是通过LTW还是CTW使用基于代理的Spring AOP或原生AspectJ?请提供更多信息,以便使问题可以重现。 – kriegaex 2015-03-14 13:27:10

+0

你好@kriegaex。非常感谢您的关注,首先。实际上,如果我在Eclipse中创建一个新的工作区并从头开始构建测试用例,它就可以工作。所以看起来有些东西正在污染我的类路径。我将用请求的信息更新问题。 – 2015-03-16 07:37:57

+1

我不明白为什么你需要* AspectJ Maven插件*用于Spring AOP。你只需要AspectJ,而不是Spring AOP,因为后者不会编译任何东西,只是使用动态代理。也许你试图一次以两种方式应用相同的方面。确实很奇怪。顺便说一下,* aspectjweaver.jar *仅用于AspectJ加载时编织,而不用于compile.time编织。无论如何,即使您使用AspectJ,在这种情况下也是多余的。 – kriegaex 2015-03-16 19:35:01

回答

0

最后,我得到它的工作。看来Eclipse在我的类路径中做了一些混乱,导致了上面的问题。我删除了aspectjweaver,我可以得到工作如下代码,总部设在@ DavidL的回答是:

@Aspect 
public class PerformanceMonitorAspect { 

    /** 
    * Decide whether the Pointcut to be executed or not 
    */ 
    private static boolean enabled; 

    @Pointcut("execution(* com.company.MyService+.*(..)) && if()") 
    public static boolean pointCut() { 
     return enabled; 
    } 

    private Logger logger = LoggerFactory.getLogger("performance"); 

    @Around("pointCut()") 
    public Object profileServiceMethods(ProceedingJoinPoint thisJoinPoint) throws Throwable { 
     MethodSignature ms = (MethodSignature) thisJoinPoint.getSignature(); 
     Method m = ms.getMethod(); 
     long t1 = System.nanoTime(); 
     Object result = thisJoinPoint.proceed(); 
     long t2 = System.nanoTime(); 
     long millis = TimeUnit.NANOSECONDS.toMillis(t2 - t1); 
     if (millis < 1000) { 
      logger.trace("Execution time for {}: {} ms", m.getName(), millis); 
     } else { 
      logger.warn("Substantial execution time for {}: {} ms", m.getName(), 
        millis); 
     } 
     return result; 
    } 

    //The value is retrieved by Spring having read a config file written by Maven, depending on the profile 
    @Value("${enable.performance.monitor}") 
    public void setEnabled(boolean value) { 
     enabled = value; 
    } 

} 

然后,让Spring管理方面:

<bean class="com.tadic.aspects.PerformanceMonitorAspect" factory-method="aspectOf" /> 
1

您可以获得对代表您当前舞台的属性(可能以静态方式)的引用。根据它的值,你可以绕过profileServiceMethods方法中的代码(提前返回)。

在一个不太美观的方式,你可以在你的方面声明一个布尔值VAR为同一目的:

if(!logActivated) 
    return null; 
else 
    <your code here> 

编辑:

只是来看看文档。也许你可以这样做:

@Pointcut("execution(* com.company.MyService+.*(..)) && args(i) && if()") 
public static boolean pointCut(int i) { 
    return i == State.PRODUCTION_STAGE ; 
} 
+0

我刚刚编辑我的帖子,包括尝试与您的作品的代码。这似乎是一个好主意,但不能得到它的工作:-( – 2015-03-13 14:19:51

+0

看起来它可能是合规性水平问题。检查[这里](http://aspectj.2085585.n4.nabble.com/Stackmap- frame-errors-when-building-the-aspectj-project-with-Java-1-7-td4651609.html)和[here](http://heshans.blogspot.ca/2014/10/stackmap-frame-errors -when-building.html)以获取更多信息 – DavidL 2015-03-13 14:34:33