关于Java:Aspect不适用于带有外部jar的Spring Boot应用程序

Aspect does not work with Spring boot application with external jar

我正在尝试创建一个用于测量方法运行时间的计时器方面。

我创建了一个名为@Timer的注释:

1
2
3
4
5
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.TYPE})
public @interface Timer {
    String value();
}

然后,我创建了如下方面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Aspect
public class MetricAspect {

    @Autowired
    private MetricsFactory metricsFactory;

    @Pointcut("@annotation(my.package.Timer)")
    public void timerPointcut() {}

    @Around("timerPointcut()")
    public Object measure(ProceedingJoinPoint joinPoint) throws Throwable {
       /* Aspect logic here */
    }

    private Timer getClassAnnotation(MethodSignature methodSignature) {
        Timer annotation;
        Class< ? > clazz = methodSignature.getDeclaringType();
        annotation = clazz.getAnnotation(Timer.class);
        return annotation;
    }

我有一个配置类,如下所示:

1
2
3
4
5
6
7
8
9
@Configuration
@EnableAspectJAutoProxy
public class MetricsConfiguration {

    @Bean
    public MetricAspect notifyAspect() {
        return new MetricAspect();
    }
}

直到这里的所有内容都在打包的jar中定义,我在Spring Boot应用程序中将其用作依赖项

在我的Spring Boot应用程序中,导入MetricsConfiguration,调试代码,然后看到创建了MetricAspect bean。

我在代码中如下使用它:

1
2
3
4
5
6
7
8
9
10
11
@Service
public class MyService {
    ...

    @Timer("mymetric")
    public void foo() {
       // Some code here...
    }

    ...
}

但是我的代码没有达到measure方法。 不知道我在想什么。

为了完成图片,我在pom文件中添加了以下依赖项:

1
2
3
4
5
6
7
8
9
10
11
12
13
<dependencies>
    <dependency>
        <groupId>org.aspectj</groupId>
        aspectjweaver</artifactId>
        <version>1.7.4</version>
    </dependency>

    <dependency>
        <groupId>org.aspectj</groupId>
        aspectjrt</artifactId>
        <version>1.7.4</version>
    </dependency>
</dependencies>

那就是导入MetricsConfiguration@Configuration类:

1
2
3
4
5
6
7
@Configuration
@EnableAspectJAutoProxy
@Import(MetricsConfiguration.class)
@PropertySource("classpath:application.properties")
public class ApplicationConfiguration {

}

它由Spring的自动配置加载加载。


@Component@Configurable可以解决您的问题吗?

1
2
3
4
5
@Aspect
@Component
public class yourAspect {
 ...
}

启用S??pring AOP或AspectJ

编辑:

我创建了一个项目来模拟您的问题,毕竟似乎没有问题。是否受其他问题影响?

https://github.com/zerg000000/spring-aspectj-test


我无法使用AspectJ 1.8.8和spring 4.2.5重现您的问题。这是我的Maven多模块方法,其方面在单独的jar中。

我稍微修改了您的代码,但未更改任何注释。唯一可能不同的是,我添加了org.springframework:spring-aop依赖项并按如下所示定义了入口点:

1
2
3
4
5
6
7
8
9
10
11
@Import(MetricsConfiguration.class)
@SpringBootApplication
public class Application {
    // @Bean definitions here //

    public static void main(String[] args) throws InterruptedException {
        ApplicationContext ctx =
            SpringApplication.run(Application.class, args);
        ctx.getBean(MyService.class).doWork();
    }
}


  • 如果外部jar是Spring boot starter,则可以在AutoConfiguration中配置Aspect bean:
  • (1)

    1
    2
    3
    4
    @Aspect
    public class MyAspect {
      //....
    }

    (2)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    package a.b.c

    @Configuration
    public class MyAutoConfiguration {
        @Bean
        MyAspect myAspect() {
            return new MyAspect();
        }  
    }

    (3)在spring.factories中配置

    1
    2
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\\
    a.b.c.MyAutoConfiguration
  • 如果外部jar不是Spring启动启动器,只需将Aspect作为bean加载,则可以使用@ComponentScan

  • 我有一个类似的问题,方面是在jar库中构建的,而spring-boot应用程序在其他地方。原来,spring-boot应用程序和jar库的软件包不同。由于这个原因,Spring并没有考虑将库的程序包自动装配到应用程序上下文中。

    因此,必须在Application.java中包含@ComponentScan({"base.package.application.*","base.package.library.*"})


    即使有详细的日志记录,在切入点本身有问题时也无法调试spring-boot Aspectj方面:如何调试Spring AOP

    不幸的是,带有注释的spring boot + spring-aop并没有很多调试方面的方法,以及为什么不扫描某些类,尤其是非spring compoment jar类,例如其类在抽象类或静态final方法中的jar类。需要正确的切入点以覆盖所有类/实现,即使它们是组件扫描的。

    调试Asepct的最佳方法(或使用核心AOP并避免spring-aop)是使用LTW Aspectj Weaver使用org / aspectj / aop.xml或META-INF / aop.xml进行配置控制来启用aop.xml。
    -Daj.weaving.verbose = true -javaagent:?/ .m2 / repository / org / aspectj / aspectjweaver / 1.9.5 / aspectjweaver-1.9.5.jar

    要使用调试/详细日志调试所有方面/类,以查看为什么未扫描某些类:
    ...

    这几乎总是可以帮助解决切入点或类未被选择的问题。

    或者,仅使用LTW aop,请参阅https://github.com/dsyer/spring-boot-aspectj


    添加此componentScan以解决问题。

    1
    2
    3
    4
    5
    6
    7
    8
    @ComponentScan("package.of.aspect")
    @Configuration
    @EnableAspectJAutoProxy
    @Import(MetricsConfiguration.class)
    @PropertySource("classpath:application.properties")
    public class ApplicationConfiguration {

    }

    根据mojohaus的解释,您必须将如下所示的构建设置添加到Woven方面,并将其编织到实现方面接口的所有类中。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                aspectj-maven-plugin</artifactId>
                <version>1.11</version>
                <configuration>
                    <complianceLevel>1.8</complianceLevel>
                    <includes>
                        <include>**/*.java</include>
                        <include>**/
    *.aj</include>
                    </includes>
                    src/main/aspect</aspectDirectory>
                    <testAspectDirectory>src/test/aspect</testAspectDirectory>
                    <XaddSerialVersionUID>true</XaddSerialVersionUID>
                    <showWeaveInfo>true</showWeaveInfo>
                   
                       
                            <groupId>your aspect groupId</groupId>
                            your aspect artifactId</artifactId>
                        </aspectLibrary>
                    </aspectLibraries>
                </configuration>
                <executions>
                    <execution>
                        <id>compile_with_aspectj</id>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>test-compile_with_aspectj</id>
                        <goals>
                            <goal>test-compile</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        aspectjtools</artifactId>
                        <version>${aspectj.runtime.version}</version>
                    </dependency>
                    <dependency>
                        <groupId>your aspect groupId</groupId>
                        youar aspect artifactId</artifactId>
                        <version>1.0.0-SNAPSHOT</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>