Preface
The previous article mainly about how to implement an SPI with interceptor function at 1618a157ae8884. Let’s talk about how the custom SPI integrates with spring today.
Thinking: What do we need to integrate spring into the SPI we implement? Or what features of spring should we use to achieve what we have?
In addition to the well-known IOC and AOP, spring also provides a wealth of extension points, such as various post processors. Today we will talk about topics that are relatively familiar to everyone, how to use custom annotations to convert SPI Inject into the spring container
Integrated thinking
1. Custom annotations
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Activate {
String value() default "";
}
2. Custom bean definition 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. Define 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. Custom 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 {};
}
Sample demo
1. Add @Activate annotation to the class that needs to be injected into the spring container
@Activate("hello-mysql")
public class SpringMysqlDialect implements SpringSqlDialect {
@Autowired
private MysqlDialectService mysqlDialectService;
@Override
public String dialect() {
return mysqlDialectService.dialect();
}
}
2. Add the scan SPI range annotation to the startup class
@SpringBootApplication(scanBasePackages = "com.github.lybgeek")
@EnableSpi(basePackages = "com.github.lybgeek")
public class SpiTestApplication implements ApplicationRunner
3. Use getBeansOfType to verify
applicationContext.getBeansOfType(SpringSqlDialect.class)
.forEach((beanName,bean) -> System.out.println(beanName + "-->" + bean));
The print result is as follows
hello-mysql-->com.github.lybgeek.dialect.mysql.SpringMysqlDialect@433348bc
Description has been injected into the spring container
Summarize
Hosting the project's services to the spring ioc container can be regarded as a relatively basic action to integrate with spring. This article demonstrates also a relatively basic link. The strength of spring lies in its scalability. In the life cycle of spring beans, basically Extension points can be seen everywhere, interested friends can experience the verification by themselves
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。