preface

The last article focused on implementing an SPI with interceptor functionality. Today we’ll talk about how the custom SPI integrates with Spring.

Think: What does our implementation of SPI integrate with Spring? Or what features of Spring are we going to use to achieve what we want?

In addition to being well known for IOC and AOP, Spring also provides a wealth of extension points, such as various back-end processors. Today we will talk about the relatively familiar topic of how to inject SPI into the Spring container through custom annotations

Integrated thinking

1. Custom annotations

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Activate {

    String value(a) default "";
}

Copy the code

2. Custom beans define scanners

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());
    }
Copy the code

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));
    }
Copy the code

4. Customize the 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 {};
}
Copy the code

Example demonstrates

Add the @Activate annotation to the class that you want to inject into the Spring container

@Activate("hello-mysql")
public class SpringMysqlDialect implements SpringSqlDialect {

    @Autowired
    private MysqlDialectService mysqlDialectService;

    @Override
    public String dialect(a) {
        returnmysqlDialectService.dialect(); }}Copy the code

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 
Copy the code

3. Use getBeansOfType for verification

 applicationContext.getBeansOfType(SpringSqlDialect.class)
                .forEach((beanName,bean) -> System.out.println(beanName + "-- >" + bean));
Copy the code

The print result is as follows

hello-mysql-->com.github.lybgeek.dialect.mysql.SpringMysqlDialect@433348bc
Copy the code

It has been injected into the Spring container

conclusion

Hosting the project’s services to the Spring IOC container can be regarded as a relatively basic action to integrate with Spring, and this demonstration is also a relatively basic part. The strength of Spring lies in its extensibility. Extension points can be seen everywhere in the life cycle of Spring beans. Interested friends can later experience their own verification

The demo link

Github.com/lyb-geek/sp…