摘要:
主要介绍了
ImportBeanDefinitionRegistrar接口来实现动态注册bean对象,交给spring ioc进行管理,常用两种方式,第一种直接手动注册对象,第二种扫描包的方式按照指定的注解。
ImportBeanDefinitionRegistrar简介
spring官方的@Component、@Service等注解的动态注入机制就依赖于它。具体实现一个ImportBeanDefinitionRegistrar的实现类,然后在@Import导入配置类,注意必须要有@Configuration的配置类上,@SpringBootApplication注解已经包含了@Configuration,下文的例子就配置在启动类上。
使用案例
动态注册单一的bean对象
PrintHandler类
@Data
public class PrintHandler {
private static final Logger log = LoggerFactory.getLogger(PrintHandler.class);
private String desc;
public void print(String data){
log.info("[" + this.desc + "] --->" + data);
}
}
PrintRegistrarConfig类
public class PrintRegistrarConfig implements ImportBeanDefinitionRegistrar {
private static final Logger log = LoggerFactory.getLogger(InterceptorRegistrarConfig.class);
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
log.info("开始动态注册bean");
BeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClassName(PrintHandler.class.getName());
MutablePropertyValues values = beanDefinition.getPropertyValues();
values.addPropertyValue("desc","动态注册");
registry.registerBeanDefinition("printHandler",beanDefinition);
}
}
#### 注意事项
> 进行对象注册的时候,对象里面的属性只能通过`beanDefinition.getPropertyValues();`来进行设置属性值,因为这样`spring`才能进行对象的三级缓存管理。
RegistrarApplication类配置
重点是
@Import(InterceptorRegistrarConfig.class)这一行,导入配置
@Import(InterceptorRegistrarConfig.class)
@SpringBootApplication
public class RegistrarApplication {
public static void main(String[] args) {
SpringApplication.run(RegistrarApplication.class, args);
}
}
AnyPrintController 控制器编写
@RestController
@RequestMapping(value = "any-print")
public class AnyPrintController {
@Autowired
private PrintHandler printHandler;
@AnyPrint
@GetMapping("hello")
public Object hello(String desc){
printHandler.print(desc);
return "hello";
}
}
测试
- 访问
curl http://127.0.0.01:8080/any-print/hello?desc=zhangsan
- 结果
仿照@Service注解扫描指定包下的所有有注解@OpenApi的类注册为Spring的Bean对象
在该注解标注的类中可以使用和
spring所有一致的功能
OpenApi注解
@Documented
@Inherited
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface OpenApi {
}
PrintOpenApi类
下面我注入了一个
AnyPrintService,你可以换成任何你自己定义的对象,由于bean的管理交给了spring,所以可以无差别使用对象注入
@OpenApi
public class PrintOpenApi {
@Autowired
private AnyPrintService anyPrintService;
private static final Logger log = LoggerFactory.getLogger(PrintOpenApi.class);
public void print(String data){
log.info("this is print open api : "+ data);
anyPrintService.hello();
}
}
OpenApiClassPathBeanDefinitionScanner扫描注解类
public class OpenApiClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {
public OpenApiClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
super(registry, useDefaultFilters);
}
protected void registerFilters () {
/**
* TODO addIncludeFilter 满足任意includeFilters会被加载
*/
addIncludeFilter(new AnnotationTypeFilter(OpenApi.class));
/**
* TODO addExcludeFilter 同样的满足任意excludeFilters不会被加载
*/
// addExcludeFilter(new AnnotationTypeFilter(MyService.class));
}
@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
return super.doScan(basePackages);
}
}
OpenApiBeanDefinitionRegistrar注册bean到spring
public class OpenApiBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanFactoryAware {
private ResourceLoader resourceLoader;
private BeanFactory beanFactory;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
OpenApiClassPathBeanDefinitionScanner scanner = new OpenApiClassPathBeanDefinitionScanner(registry,false);
scanner.setResourceLoader(this.resourceLoader);
scanner.registerFilters();
scanner.doScan("com.github.huzhihui.registrar.openapi");
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
测试类
@RestController
@RequestMapping(value = "open-api")
public class OpenApiController {
@Autowired
private PrintOpenApi printOpenApi;
@GetMapping(value = "print")
public Object print(String data){
printOpenApi.print(data);
return "SUCCESS";
}
}
- 测试
curl http://localhost:8080/open-api/print?data=123