如何在Spring自定义注解内部引用参数值扩展@ComponentScan扫描范围
首先明确结论:Java注解本身是静态编译的元数据,无法直接在自定义注解内部的元注解(比如你写的@ComponentScan)中引用自定义注解的属性值,我们可以通过Spring提供的扩展能力实现「默认公共包+用户自定义传入包」合并扫描的需求,以下是可直接落地的实现方案:
实现方案
第一步:调整自定义@Microservice注解结构
移除硬编码的@ComponentScan,导入后续我们要写的自定义包扫描处理器:
@SpringBootApplication @ServletComponentScan(basePackages = "com.example.commons.traceability") @Import(CustomPackageScanProcessor.class) @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Microservice { String[] scanBasePackages() default {}; }
第二步:编写自定义包扫描处理器
该处理器会自动识别启动类上@Microservice注解传入的扫描包,和默认公共包合并后执行扫描:
import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.env.Environment; import org.springframework.core.env.EnvironmentAware; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; public class CustomPackageScanProcessor implements BeanDefinitionRegistryPostProcessor, EnvironmentAware { private Environment environment; @Override public void setEnvironment(Environment environment) { this.environment = environment; } @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { // 查找标注了@Microservice的启动类 Map<String, Object> startupBeans = registry.getBeansWithAnnotation(Microservice.class); if (startupBeans.isEmpty()) { return; } Object startupBean = startupBeans.values().iterator().next(); Microservice microserviceAnno = AnnotationUtils.findAnnotation(startupBean.getClass(), Microservice.class); if (microserviceAnno == null) { return; } // 合并默认公共包和用户传入的自定义包 List<String> allScanPackages = new ArrayList<>(Arrays.asList( "com.example.commons.security", "com.example.commons.restTemplate", "com.example.commons.logging" )); allScanPackages.addAll(Arrays.asList(microserviceAnno.scanBasePackages())); // 执行包扫描 ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry, true, environment); scanner.scan(allScanPackages.toArray(new String[0])); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { // 无需额外逻辑 } }
第三步:按你预期的方式使用即可
启动类的写法和你给出的示例完全一致:
@Microservice(scanBasePackages = {"com.example.myproject"}) public class MySpringApplication { public static void main(String[] args) { SpringApplication.run(MySpringApplication.class, args); } }
此时Spring会同时扫描3个默认公共包和你传入的com.example.myproject包,完全满足需求。
内容的提问来源于stack exchange,提问作者aeroboy
相关产品推荐
相关产品推荐

