在没有外部依赖的情况下将具有编译时编织功能的AspectJ应用于Spring Boot应用程序

时间:2019-04-05 08:43:49

标签: java spring spring-boot aspectj compile-time-weaving

我正在设置一个 SpringBoot应用程序 ,该应用程序应在命令行上执行。 该应用程序包含多个CommandLineRunner,如果所需的选项是通过命令行执行传递的,则它们将运行其特定的逻辑。 我使用 Gradle 作为构建工具。

每个运行器中都有一个初始化方法来解析选项并在没有传递选项的情况下打印出帮助语句,我将其外包给方面类。
问题就是这样开始的。

起初,我已经使用 Spring AOP 成功地进行了尝试,但这不是一个选择,因为我也想将私有方法与我的方面绑定。 因此,我必须使用功能更强大的AspectJ来实现。

不幸的是, AspectJ加载时编织 对我来说不是一个选择,因为它需要在执行jar时将jvm参数传递给命令行,我想避免。

所以从我现在所看到的来看,只有 AspectJ编译时编织 AspectJ编译后编织 向左。

AspectJ的编译时编织对我来说似乎是最合适的选择,但是不幸的是,必须使用io.freefair中的以下插件。
链接:https://plugins.gradle.org/plugin/io.freefair.aspectj.compile-time-weaving
我已经尝试过了,并且工作正常, 但是我的目标是避免在项目中添加外部依赖项,因此我试图从Spring或标准Java系列中找到解决方案。

编译后编织也是如此。

我读过的每个有关编译时编织的教程或答案都是关于应用插件的。 我想知道,除了上面的io.freefair插件之外,没有找到解决我的用例的方法。

MainClass:

@SpringBootApplication
@ImportResource("classpath:spring/applicationContext.xml")
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
public class MainClass {

    /**
     * The main method.
     *
     * @param args the arguments
     */
    public static void main(String[] args) {
        SpringApplication.run(MainClass.class, args);
    }
}

我的方面类如下:

@Aspect
public class ConfigurationsAspect {

    private static final Logger logger = Logger.getLogger(ConfigurationsAspect.class);

    @Autowired
    private ConnectionWrapper connection;

    @Autowired
    private OptionHandler optionHandler;

    /**
     * Closes the connection to the Server if there were an initialized connection.
     */
    @After("execution(void tools.cli.MainClass.main(*))")
    public void closeConnection() {
        if (this.connection.isConnected()) {
            logger.debug("Closing connection");
            this.connection.close();
        }
    }                                                                                                                       

    /**
     * Parses the options if not parsed before.
     * 
     * @param jp The actual point of execution.
     */
    @Before("execution(* tools.runners.tasks.*.run(*))")
    public void parseOptions(JoinPoint jp) {
        if (!this.optionHandler.isParsed()) {
            String[] args = (String[]) jp.getArgs()[0];
            this.optionHandler.parseParameters(args);
        }
    }
}

在applicationContext.xml中描述了涉及的bean,如(片段)所示:

    <bean class="tools.aspects.ConfigurationsAspect" factory-method="aspectOf"/>    

    <bean class="tools.cli.options.OptionHandler"/>

    <bean class="tools.connection.ConnectionWrapper" />

我的build.gradle如下所示(摘要):

plugins {
    id 'org.springframework.boot' version '2.1.3.RELEASE'
    id 'java'
}

apply plugin: 'application'
apply plugin: 'io.spring.dependency-management'

dependencies {
    compile('commons-io:commons-io:2.5')    
    compile('commons-cli:commons-cli:1.4')
    compile('org.springframework.boot:spring-boot-starter')

    compile('org.springframework:spring-oxm')
    testCompile('org.springframework:spring-oxm')

    compile 'org.aspectj:aspectjrt:1.9.2'
    compile 'org.aspectj:aspectjweaver:1.9.2'
}

当我不使用io.freefair插件时收到以下错误消息。

ERROR org.springframework.boot.SpringApplication: 858 - Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'tools.aspects.ConfigurationsAspect#0' defined in class path resource [spring/applicationContext.xml]: No matching factory method found: factory method 'aspectOf()'. Check that a method with the specified name exists and that it is static.

AspectJ应该创建我的ConfigurationsAspect的一个实例,并插入AspectOf()方法,Spring正在搜索该方法是否正常运行。

引出我的问题:

是否有机会在不应用外部依赖性的情况下实现AspectJ编译时(或后编译时)编织?

如果不是这样,即使我更喜欢“编译时编织”,也有机会实现“加载时编织”,而不必传递JVM参数来正确运行jar ?


谢谢。

0 个答案:

没有答案