Preface
The last article mainly Talk about how to implement a with interceptor function SPI. Today, let's talk about custom SPI How to communicate with spring Integrate .
reflection : What we achieve SPI To integrate spring What kind of things ? Or we'll take advantage of spring What features of the implement what we ?
spring Except for the well-known IOC and AOP outside , And it also provides a wealth of extension points , For example, various post processors , Today, let's talk about the topics we are relatively familiar with , How to use custom annotations to SPI Injection into spring In the container
Integration thinking
1、 Custom annotation
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Activate {
String value() default "";
}
2、 Customize bean Define scanner
public class ActivateClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {
public ActivateClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
super(registry);
}
@SneakyThrows
@Override
protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
super.registerBeanDefinition(definitionHolder, registry);
Class clz = Class.forName(definitionHolder.getBeanDefinition().getBeanClassName());
Activate activate = AnnotationUtils.findAnnotation(clz,Activate.class);
if(ObjectUtils.isNotEmpty(activate) && StringUtils.isNotBlank(activate.value())){
String activateName = getEnvironment().resolvePlaceholders(activate.value());
registry.registerBeanDefinition(activateName,definitionHolder.getBeanDefinition());
}
}
@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
return super.isCandidateComponent(beanDefinition) && beanDefinition.getMetadata()
.hasAnnotation(Activate.class.getName());
}
3、 Definition ImportBeanDefinitionRegistrar
public class SpiRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {
private Environment environment;
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
Set<String> basePackages = this.getBasePackages(importingClassMetadata);
String[] packages = {};
SpiBeanUtils.registerActivateInstances(registry,environment,basePackages.toArray(packages));
}
4、 Customize enabled annotation
@Target(value = ElementType.TYPE)
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
@Import(SpiRegister.class)
public @interface EnableSpi {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}
Demonstration of examples
1、 In need of injection into spring Add... To the class of the container @Activate annotation
@Activate("hello-mysql")
public class SpringMysqlDialect implements SpringSqlDialect {
@Autowired
private MysqlDialectService mysqlDialectService;
@Override
public String dialect() {
return mysqlDialectService.dialect();
}
}
2、 Start class plus scan SPI scope note
@SpringBootApplication(scanBasePackages = "com.github.lybgeek")
@EnableSpi(basePackages = "com.github.lybgeek")
public class SpiTestApplication implements ApplicationRunner
3、 utilize getBeansOfType To verify
applicationContext.getBeansOfType(SpringSqlDialect.class)
.forEach((beanName,bean) -> System.out.println(beanName + "-->" + bean));
The results are as follows
hello-mysql-->[email protected]
Description has been injected into spring In the container
summary
Hosting the services of the project to spring ioc Containers , It can be compared with spring Integrate more basic actions , This demonstration is also a part of the relative foundation ,spring Strong place , Its scalability , stay spring bean In the life cycle of , Basically, extension points can be seen everywhere , Interested friends can experience and verify by themselves later