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
<code><dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<scope>runtime</scope>
</dependency>
</code>Custom Annotation
<code>@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Manufactur {
String value() default ""; // manufacturer code
}
</code>AOP Aspect
The aspect implements
EnvironmentAwareto obtain the
Environmentobject, parses the annotation on the target method, resolves the placeholder, and stores the result in a
ThreadLocal.
<code>@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;
}
}
</code>Service Usage
<code>@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;
}
}
</code>Controller Test
<code>@RestController
@RequestMapping("/business")
public class BusinessController {
@Resource
private BusinessService bs;
@GetMapping("/{id}")
public Object home(@PathVariable String id) {
return bs.invoke(id);
}
}
</code>The resolved value is stored in the
ThreadLocalby the AOP aspect and can be accessed in the service method.
With these steps, the custom annotation now supports placeholder resolution.
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.