javaspring-bootspring-aopspring-beancomponent-scan

Cannot apply library properties in Spring Boot application


I created an Java Spring library to audit and log execution times during the execution of my application. I deployed it on SonaType and load it as a dependency in a demo project.

The properties of my library could not be resolved, even if I add an auto-config file and a properties file for each feature to the library.

Here is the pom.xml of my library:

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>io.github.speedkillsx</groupId>
    <artifactId>checkcommonlib</artifactId>
    <version>0.0.5</version>
    <name>Check Common Library</name>
    <description>Demo project for Spring Boot</description>
    <packaging>jar</packaging>
    <url/>
    <licenses>
        <license>
            <name>The Apache License, Version 2.0</name>
            <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
            <distribution>repo</distribution>
        </license>
    </licenses>

    <scm>
        <connection>scm:git:git://github.com/speedKillsx/checkcommonlib.git</connection>
        <developerConnection>scm:git:ssh://git@github.com/speedKillsx/checkcommonlib.git</developerConnection>
        <url>https://github.com/speedKillsx/checkcommonlib</url>
        <tag>HEAD</tag>
    </scm>

    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <annotationProcessorPaths>
                        <path>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </path>
                    </annotationProcessorPaths>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.sonatype.central</groupId>
                <artifactId>central-publishing-maven-plugin</artifactId>
                <version>0.7.0</version>
                <extensions>true</extensions>
                <configuration>
                    <publishingServerId>ossrh</publishingServerId>
                    <autoPublish>true</autoPublish>
                    <waitUntil>published</waitUntil>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-javadoc-plugin</artifactId>
                <version>3.6.3</version>
                <executions>
                    <execution>
                        <id>attach-javadocs</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-source-plugin</artifactId>
                <version>3.2.1</version>
                <executions>
                    <execution>
                        <id>attach-sources</id>
                        <goals>
                            <goal>jar</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <!-- GPG Signing Plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-gpg-plugin</artifactId>
                <version>1.5</version>
                <executions>
                    <execution>
                        <id>sign-artifacts</id>
                        <phase>verify</phase>
                        <goals>
                            <goal>sign</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

    <distributionManagement>
        <repository>
            <id>ossrh</id>
            <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
        </repository>
        <snapshotRepository>
            <id>ossrh</id>
            <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
        </snapshotRepository>
    </distributionManagement>

</project>

My auto-configuration file in the library:

package io.github.speedkillsx.checkcommonlib.config;

import io.github.speedkillsx.checkcommonlib.properties.AuditProperties;
import io.github.speedkillsx.checkcommonlib.properties.LogExecutionTimeProperties;
import io.github.speedkillsx.checkcommonlib.properties.RetryOnFailurePropreties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * CheckCommonAutoConfiguration is a Spring configuration class that
 * auto-configures beans related to common functionalities such as
 * auditing, logging execution time, and retry mechanisms. These functionalities
 * are managed through properties prefixed with "check-common" and loaded from
 * the application's configuration file.
 *
 * It integrates configuration support for the following types of properties:
 * - {@link AuditProperties} for enabling or disabling auditing features.
 * - {@link LogExecutionTimeProperties} for enabling or disabling method execution time logging.
 * - {@link RetryOnFailurePropreties} for configuring retry mechanisms in case of failures.
 *
 * The class enables AspectJ auto-proxy support and ensures that the
 * necessary configuration beans are available for components relying on
 * these common features.
 */
@Configuration
@EnableConfigurationProperties({
        AuditProperties.class,
        LogExecutionTimeProperties.class,
        RetryOnFailurePropreties.class
})
@EnableAspectJAutoProxy
public class CheckCommonAutoConfiguration {
}

Properties files:

@Getter
@Setter
@ConfigurationProperties(prefix = "check-common")
public class AuditProperties {
    private boolean auditEnable;
}
@Getter
@Setter
@ConfigurationProperties(prefix = "check-common.retry")
public class RetryOnFailurePropreties {
    private boolean enabled;
    private int defaultMaxAttempts;
    private long defaultDelayMs;
}
@Getter
@Setter
@ConfigurationProperties(prefix = "check-common")
public class LogExecutionTimeProperties {
    private boolean logExecutionTime;
}

I have empty application.yaml and application-local.yaml in the library.

For my demo application, I added the library as a dependency:

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.testcommonlib</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <java.version>17</java.version>
    </properties>
    <repositories>
        <repository>
            <id>sonatype-releases</id>
            <url>https://oss.sonatype.org/content/repositories/releases/</url>
        </repository>
        <repository>
            <id>sonatype-snapshots</id>
            <url>https://oss.sonatype.org/content/repositories/snapshots/</url>
        </repository>
    </repositories>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.github.speedkillsx</groupId>
            <artifactId>checkcommonlib</artifactId>
            <version>0.0.5</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.38</version>
            <scope>provided</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

And my application.yaml (in demo application):

server:
  port: 8087
spring:
  application:
    name: demo

check-common:
  audit-enable: true

check-common and its propreties cannot be resolved, I don't understand why.


Solution

  • Fortunately, the source code of your library is available on Maven Central, so I could compare version 0.0.5 (which you had problems with) to 0.0.8 (which works nicely): In the older version of class CheckCommonAutoConfiguration, you forgot to declare your aspects to be @Beans or to alternatively activate component scan correctly.

    So, this minimal reproducer works:

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.4.5</version>
        <relativePath/> <!-- lookup parent from repository -->
      </parent>
    
      <groupId>com.testcommonlib</groupId>
      <artifactId>demo</artifactId>
      <version>0.0.1-SNAPSHOT</version>
    
      <properties>
        <java.version>17</java.version>
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>io.github.speedkillsx</groupId>
          <artifactId>checkcommonlib</artifactId>
          <version>0.0.8</version>
        </dependency>
        <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
          <version>1.18.38</version>
          <scope>provided</scope>
        </dependency>
      </dependencies>
    
      <build>
        <plugins>
          <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
          </plugin>
        </plugins>
      </build>
    
    </project>
    

    src/main/resources/application.yaml

    server:
      port: 8087
    spring:
      application:
        name: demo
    
    check-common:
      audit-enable: true
      log-execution-time: true
    

    src/main/java/com/testcommonlib/app/q79605952/MyController.java

    package com.testcommonlib.app.q79605952;
    
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class MyController {
      public void doSomething() {
        System.out.println("Doing something...");
      }
    }
    

    src/main/java/com/testcommonlib/app/q79605952/DemoApplication.java

    package com.testcommonlib.app.q79605952;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.context.ConfigurableApplicationContext;
    
    @SpringBootApplication
    public class DemoApplication {
      public static void main(String[] args) {
        try (ConfigurableApplicationContext appContext = SpringApplication.run(DemoApplication.class, args)) {
          doStuff(appContext);
        }
      }
    
      private static void doStuff(ConfigurableApplicationContext appContext) {
        appContext.getBean(MyController.class).doSomething();
      }
    }
    

    Console log (without timestamps, log channels, thread names etc.)

    c.t.app.q79605952.DemoApplication        : Started DemoApplication in 4.938 seconds (process running for 6.049)
    i.g.s.checkcommonlib.aspect.AuditAspect  : [AUDIT] Starting the Audit...
    i.g.s.c.aspect.LogExecutionTimeAspect    : [LogExecutionTime] Starting execution time recording for method doSomething...
    i.g.s.c.aspect.LogExecutionTimeAspect    : [LogExecutionTime] Starting execution time record : 1.74641853044E9 SECONDS
    Doing something...
    i.g.s.c.aspect.LogExecutionTimeAspect    : [LogExecutionTime] Result generated : null
    i.g.s.c.aspect.LogExecutionTimeAspect    : [LogExecutionTime] Ending execution time record : 1.746418530442E9 SECONDS
    i.g.s.c.aspect.LogExecutionTimeAspect    : [LogExecutionTime] Time elapsed during execution equals  : 0.002 SECONDS
    i.g.s.checkcommonlib.aspect.AuditAspect  : [AUDIT] Method signature: void com.testcommonlib.app.q79605952.MyController.doSomething()
    i.g.s.checkcommonlib.aspect.AuditAspect  : [AUDIT] Method name: doSomething ; Returned result null
    o.s.b.w.e.tomcat.GracefulShutdown        : Commencing graceful shutdown. Waiting for active requests to complete
    o.s.b.w.e.tomcat.GracefulShutdown        : Graceful shutdown complete
    

    The problem was not that your configuration was not picked up but that your aspects were completely inactive.