Why Your Custom Spring Advisor Fails and How to Fix It in Spring Boot 3.2

This article explores why a custom Advisor aspect may not work in Spring Boot 3.2, demonstrates how enabling @EnableAspectJAutoProxy and adjusting bean roles resolves the issue, and also covers advanced topics such as FactoryBean type conversion, version retrieval, SpringProperties, and the Spring SPI mechanism.

Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Spring Full-Stack Practical Cases
Why Your Custom Spring Advisor Fails and How to Fix It in Spring Boot 3.2

Environment: Spring Boot 3.2.5

Spring typically defines aspects using the @Aspect annotation, but you can also create low‑level Advisor beans. Even when using @Aspect, Spring ultimately converts it to an Advisor. Defining an Advisor bean alone may not take effect when @EnableTransactionManagement is active because its proxy processor is limited by the @Role annotation.

// Define an Advisor
public class LogAdvisor implements PointcutAdvisor {
    // TODO: output log before and after business method execution
    // matches any class and method
}

// Enable transaction management
@Configuration
@EnableTransactionManagement
public class TxConfig {
    @Bean
    public LogAdvisor logAdvisor() {
        return new LogAdvisor();
    }
}

// Business method
@Transactional
public void save() {
    System.out.printf("save%n");
}

Running the application shows that the custom LogAdvisor does not intercept the method.

Adding @Role(BeanDefinition.ROLE_INFRASTRUCTURE) to the Advisor bean and then enabling @EnableAspectJAutoProxy resolves the problem because the AspectJ proxy processor replaces the transaction manager’s proxy processor and has no @Role restriction.

@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public LogAdvisor logAdvisor() {}

After adding @EnableAspectJAutoProxy and removing the @Role annotation, the LogAdvisor works as expected.

@Bean
public LogAdvisor logAdvisor() {}

@EnableAspectJAutoProxy
public class ProxyConfig {}

@EnableTransactionManagement
public class TxConfig {}

Result: the custom LogAdvisor is now effective.

Spring Boot also provides convenient type‑conversion support via ConversionServiceFactoryBean, allowing you to register custom converters.

@Bean
public ConversionServiceFactoryBean csfb() {
    ConversionServiceFactoryBean bean = new ConversionServiceFactoryBean() {
        @Override
        protected GenericConversionService createConversionService() {
            return new FormattingConversionService();
        }
    };
    Set<?> converters = new HashSet<>();
    converters.add(...);
    bean.setConverters(converters);
    return bean;
}

You can retrieve the current Spring and Spring Boot versions programmatically:

public void getVersion() {
    String springVersion = SpringVersion.getVersion();
    String springBootVersion = SpringBootVersion.getVersion();
}

SpringVersion reads the Implementation‑Version attribute from META‑INF/MANIFEST.MF, while SpringBootVersion#getVersion() returns the version string directly.

Spring also exposes a global configuration file via SpringProperties , which reads a spring.properties file from the classpath root. Common properties include spring.beaninfo.ignore, spring.getenv.ignore, and newer ones such as spring.context.checkpoint and spring.context.exit.

# Enable faster startup
spring.beaninfo.ignore
# Ignore system environment variables
spring.getenv.ignore
# Default compiler mode for SpEL expressions
spring.expression.compiler.mode
# ... other properties ...

The Spring SPI mechanism uses SpringFactoriesLoader to load factory implementations from META-INF/spring.factories files on the classpath. The file maps an interface or abstract class name to a comma‑separated list of implementation class names.

com.pack.CommonService=com.pack.MyCommonService1,com.pack.MyCommonService2

Implementation classes must have an instantiable constructor (single, public, or default). If the constructor requires arguments, an ArgumentResolver should be provided; a FailureHandler can customize error handling. You can also load factories from a custom location:

List<CommonService> services = SpringFactoriesLoader
    .forResourceLocation("com/pack/spi/pack.factories")
    .load(CommonService.class);
System.out.println(services);
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Spring BootFactoryBeanAdvisorSpring SPIVersion Retrieval
Spring Full-Stack Practical Cases
Written by

Spring Full-Stack Practical Cases

Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.