我正在尝试为Spring框架编写自己的@Enable
批注,该批注应如下使用:
package com.example.package.app;
@SpringBootApplication
@com.example.annotations.EnableCustom("com.example.package.custom")
public class MyApplication {}
我关注了
Component scan using custom annotation,但这带来了一些限制:
"com.example.package.base"
,但需要在配置中预定义包。
我看了@AliasFor
,但是无法正常工作。
com.example.annotations
中的类的bean,而不扫描com.example.package.*
。
我看了在EntityScanPackages.Registrar.class
批注中导入的@EntityScan
,但这是一个内部类,我的批注无法导入。
如果将
@ComponentScan(includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, value = MyAnnotation.class))
放在
MyApplication
类上,则一切正常,但是当将其移至
@EnableCustom
的元注释时,它将停止工作。如何告诉Spring Framework将
@EnableCustom
视为通过一些默认值指定
@ComponentScan
的另一种方式。我尝试使用
@Configuration
,
@Component
和其他注释进行元注释,但无济于事:
@Configuration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@ComponentScan(
includeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
value = ApplicationService.class))
public @interface EnableApplicationServices {
@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] value() default {};
}
在哪里可以找到有关此文档的文档,或者您会推荐什么起点?我的长期目标是拥有一个可以被多个项目使用的Spring Boot启动器。
在以下存储库中可以找到M(N)WE:
https://github.com/knittl/stackoverflow/tree/spring-enable-annotation
这是包结构的简要说明:
// com.example.annotations.EnableCustom.java
@Configuration
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
// this annotation is never honored:
@ComponentScan(
includeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
value = MyAnnotation.class))
//@Import(EnableCustom.EnableCustomConfiguration.class)
public @interface EnableCustom {
// this annotation works in combination with @Import, but scans the wrong packages.
@ComponentScan(
includeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
value = MyAnnotation.class))
class EnableCustomConfiguration {}
}
// file:com.example.app.Application.java
@SpringBootApplication
@EnableCustom("com.example.app.custom.services")
// @ComponentScan(
// includeFilters = @ComponentScan.Filter(
// type = FilterType.ANNOTATION,
// value = MyAnnotation.class)) // <- this would work, but I want to move it to a custom annotation
public class Application {
}
// file:com.example.app.custom.services.MyService
@MyAnnotation
public class MyService {
public MyService() {
System.out.println("Look, I'm a bean now!");
}
}
// file:com.example.annotations.services.WrongService.java
@MyAnnotation
public class WrongService {
public WrongService() {
System.out.println("I'm in the wrong package, I must not be instantiated");
}
}
解决方案如下:
将自定义注释@EnableAnnotation与 basePackages 属性一起使用
@EnableAnnotation(basePackages = "write-here-a-base-package")
@Configuration
@EnableAutoConfiguration
@ComponentScan
public class SampleSimpleApplication implements CommandLineRunner {
public static void main(String[] args) throws Exception {
SpringApplication.run(SampleSimpleApplication.class, args);
}
}
@EnableAnnotation 的定义如下:
@Retention(RUNTIME)
@Target(TYPE)
@Import(EnableAnnotationConfigRegistrar.class)
public @interface EnableAnnotation {
String[] basePackages() default "*";
@AliasFor(annotation = Import.class, attribute = "value")
Class<?>[] value() default { EnableAnnotationConfigRegistrar.class };
}
最后,
EnableAnnotationConfigRegistrar.class 以编程方式进行扫描:
public class EnableAnnotationConfigRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata enableAnnotationMetadata,
BeanDefinitionRegistry registry) {
AnnotationAttributes enableAnnotationAttributes = new AnnotationAttributes(
enableAnnotationMetadata.getAnnotationAttributes(EnableAnnotation.class.getName()));
String[] basePackages = enableAnnotationAttributes.getStringArray("basePackages");
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(basePackages);
}
}