Enable Placeholder Expressions in Custom SpringBoot Annotations
Learn how to create a custom SpringBoot annotation that supports ${…} placeholder expressions by adding AspectJ dependencies, defining the annotation, implementing an AOP aspect that resolves placeholders via EnvironmentAware, storing the result in a ThreadLocal, and using it in a service and controller.
Environment: SpringBoot 2.3.8.RELEASE with JDK 1.8.
This tutorial shows how to enable ${...} placeholder expressions in a custom annotation within a SpringBoot application.
Dependencies
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<scope>runtime</scope>
</dependency>Custom Annotation
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Manufactur {
String value() default ""; // manufacturer code
}AOP Aspect
The aspect implements EnvironmentAware to obtain the Environment object, parses the annotation on the target method, resolves the placeholder, and stores the result in a ThreadLocal.
@Component
@Aspect
public class ManufacturAspect implements EnvironmentAware {
private static final Logger logger = LoggerFactory.getLogger(ManufacturAspect.class);
private Environment environment;
@Pointcut("@annotation(com.pack.annotation.Manufactur)")
private void info() {}
@Before("info()")
public void execBefore(JoinPoint jp) {
MethodSignature sign = (MethodSignature) jp.getSignature();
Method method = sign.getMethod();
Manufactur manu = method.getAnnotation(Manufactur.class);
String value = manu.value();
logger.info("获取到注解值:{}", value);
BusinessService.code.set(this.environment.resolvePlaceholders(value));
}
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}Service Usage
@Service
public class BusinessService {
public static ThreadLocal<String> code = new ThreadLocal<>();
private static Logger logger = LoggerFactory.getLogger(BusinessService.class);
@Manufactur("${manufactur.code}-#{1 + 3}")
public String invoke(String id) {
String sno = code.get();
logger.info("自定义注解动态获取属性值:{}", sno);
// todo
return sno;
}
}Controller Test
@RestController
@RequestMapping("/business")
public class BusinessController {
@Resource
private BusinessService bs;
@GetMapping("/{id}")
public Object home(@PathVariable String id) {
return bs.invoke(id);
}
}The resolved value is stored in the ThreadLocal by the AOP aspect and can be accessed in the service method.
With these steps, the custom annotation now supports placeholder resolution.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
