基于 Spring Core 的方法
首先,我想向您展示一个不使用 Spring Boot 自动配置工具的独立应用程序。我希望你会感激春天为我们做了多少。
我们的想法是建立一个ConfigurableBeanFactory
能够StringValueResolver
了解我们的上下文(特别是application.yaml
属性)的设置。
class Application {
public static void main(String[] args) {
// read a placeholder from CustomAnnotation#foo
// foo = "${my.value}"
CustomAnnotation customAnnotation = AnnotatedClass.class.getAnnotation(CustomAnnotation.class);
String foo = customAnnotation.foo();
// create a placeholder configurer which also is a properties loader
// load application.properties from the classpath
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setLocation(new ClassPathResource("application.properties"));
// create a factory which is up to resolve embedded values
// configure it with our placeholder configurer
ConfigurableListableBeanFactory factory = new DefaultListableBeanFactory();
configurer.postProcessBeanFactory(factory);
// resolve the value and print it out
String value = factory.resolveEmbeddedValue(foo);
System.out.println(value);
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface CustomAnnotation {
String foo() default "foo";
}
@CustomAnnotation(foo = "${my.value}")
class AnnotatedClass {}
基于 Spring Boot 的方法
现在,我将演示如何在您的 Spring Boot 应用程序中执行此操作。
我们将注入ConfigurableBeanFactory
(已经配置)并解析值,类似于前面的代码片段。
@RestController
@RequestMapping("api")
public class MyController {
// inject the factory by using the constructor
private ConfigurableBeanFactory factory;
public MyController(ConfigurableBeanFactory factory) {
this.factory = factory;
}
@GetMapping(path = "/foo")
public void foo() {
CustomAnnotation customAnnotation = AnnotatedClass.class.getAnnotation(CustomAnnotation.class);
String foo = customAnnotation.foo();
// resolve the value and print it out
String value = factory.resolveEmbeddedValue(foo);
System.out.println(value);
}
}
我不喜欢在业务逻辑代码中混合低级 Spring 组件,例如BeanFactory
,所以我强烈建议我们将类型缩小到StringValueResolver
并注入它。
@Bean
public StringValueResolver getStringValueResolver(ConfigurableBeanFactory factory) {
return new EmbeddedValueResolver(factory);
}
调用方法是resolveStringValue
:
// ...
String value = resolver.resolveStringValue(foo);
System.out.println(value);
基于代理的方法
我们可以编写一个基于接口类型生成代理的方法;它的方法将返回解析的值。
这是该服务的简化版本。
@Service
class CustomAnnotationService {
@Autowired
private StringValueResolver resolver;
public <T extends Annotation> T getAnnotationFromType(Class<T> annotation, Class<?> type) {
return annotation.cast(Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class<?>[]{annotation},
((proxy, method, args) -> {
T originalAnnotation = type.getAnnotation(annotation);
Object originalValue = method.invoke(originalAnnotation);
return resolver.resolveStringValue(originalValue.toString());
})));
}
}
注入服务并使用如下:
CustomAnnotation customAnnotation = service.getAnnotationFromType(CustomAnnotation.class, AnnotatedClass.class);
System.out.println(customAnnotation.foo());