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.
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.
<code>// 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");
}</code>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.
<code>@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public LogAdvisor logAdvisor() {}
</code>After adding @EnableAspectJAutoProxy and removing the @Role annotation, the LogAdvisor works as expected.
<code>@Bean
public LogAdvisor logAdvisor() {}
@EnableAspectJAutoProxy
public class ProxyConfig {}
@EnableTransactionManagement
public class TxConfig {}
</code>Result: the custom LogAdvisor is now effective.
Spring Boot also provides convenient type‑conversion support via ConversionServiceFactoryBean, allowing you to register custom converters.
<code>@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;
}
</code>You can retrieve the current Spring and Spring Boot versions programmatically:
<code>public void getVersion() {
String springVersion = SpringVersion.getVersion();
String springBootVersion = SpringBootVersion.getVersion();
}
</code>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 .
<code># 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 ...
</code>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.
<code>com.pack.CommonService=com.pack.MyCommonService1,com.pack.MyCommonService2</code>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:
<code>List<CommonService> services = SpringFactoriesLoader
.forResourceLocation("com/pack/spi/pack.factories")
.load(CommonService.class);
System.out.println(services);
</code>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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.