복붙노트

[SPRING] 환경 변수 또는 속성에 따라 PointCut 실행

SPRING

환경 변수 또는 속성에 따라 PointCut 실행

저는 서비스 운영 성능을 모니터링하는 데 사용할 수있는 멋진 Spring Aspect를 개발했습니다. 일부 작업을 실행하는 데 시간이 오래 걸리면 작업이 기록됩니다.

@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 Advice이므로 Spring은 프로파일 링을 위해 모든 메소드 호출을 제어합니다. 디버깅하는 동안 약간의 불편 함 (Eclipse 자체를 오독하는 것조차도)이 있기 때문에, 내 애플리케이션이 생산 단계에있을 때만 Pointcut을 실행하고 싶습니다. 환경 변수, Java 속성 또는 similars에 따라 조건부로 실행되도록 Pointcut을 구성 할 수 있습니까?

문서는 메소드 변수 조건만을 참조합니다 ... 미리 감사드립니다!

편집하다

@ DavidL의 제안에 따라 필자는 pointcut을 다음과 같이 변경했습니다.

@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)

그래서 위버가 제대로하지 않는 것 같습니다. 어떤 제안?

EDIT 2 이 문제는 Spring AOP 프록시 기반 aspect를 통해 AspectJ를 사용할 때 발생한다. Maven을 사용하여 프로젝트를 빌드하고 이클립스 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은 제가 작성한 기능적인 테스트 케이스를위한 것입니다. 현재 진행중인 프로젝트는 거대하며 문제를 일으키는 다른 의존성이있는 것으로 보입니다.

해결법

  1. ==============================

    1.현재 스테이지를 나타내는 속성에 대한 참조 (정적 인 방식으로)를 얻을 수 있습니다. 값에 따라 profileServiceMethods 메서드 내부에서 코드를 무시할 수 있습니다 (조기 반환).

    현재 스테이지를 나타내는 속성에 대한 참조 (정적 인 방식으로)를 얻을 수 있습니다. 값에 따라 profileServiceMethods 메서드 내부에서 코드를 무시할 수 있습니다 (조기 반환).

    덜 세련된 방식으로, 같은 목적을 위해 aspect에서 boolean 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 ;
    }
    
  2. ==============================

    2.마지막으로, 나는 그것을 작동 시켰습니다. 위의 문제를 일으키는 이클립스가 클래스 패스에서 다소 혼란을 일으키고있는 것 같습니다. 나는 aspectjweaver를 제거했고 @ DavidL의 답변에 기반하여 다음 코드를 사용할 수 있습니다.

    마지막으로, 나는 그것을 작동 시켰습니다. 위의 문제를 일으키는 이클립스가 클래스 패스에서 다소 혼란을 일으키고있는 것 같습니다. 나는 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이 aspect를 관리하게합니다 :

    <bean class="com.tadic.aspects.PerformanceMonitorAspect" factory-method="aspectOf" />
    
  3. from https://stackoverflow.com/questions/29033690/executing-pointcut-depending-on-environment-variable-or-property by cc-by-sa and MIT license