1. Introduction

Mybatis: How to inject Mapper interface into Spring IoC? Let’s say you implement an @Controller-like annotation (or inherit a unified interface) to do things like unified injection of scheduled tasks or unified injection of Websocket processors that dynamically inject common beans.

/ / to imitate the Controller
@XBean(description = "ETL JOB")
public class JobShedule {

    @Caller(cron = "* * 0/5 * * ?" )
    public void exec(a){
        // job }}Copy the code

The above pseudocode is a timed task Bean that mimics Controller.

2. Design ideas

I have summarized the detailed development and design ideas, you can achieve this function as long as the students step by step.

2.1 Define scan annotations

Define a similar @ MappScan for import custom ImportBeanDefinitionRegistrar, and specify the range scan pack.

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Import(XBeanDefinitionRegistrar.class)
public @interface XBeanScan {

    String[] basePackages();
}
Copy the code

We have a custom scan annotation @xbeanscan. It does two things:

  • throughbasePackagesSpecifies the range of packets to scan.
  • Import our customImportBeanDefinitionRegistrarThe implementation of theXBeanDefinitionRegistrar.

2.2 Define a common tag for the target Bean

Typically we can choose an identity interface, all of whose implementation classes are injected into Spring IoC; Or, with a more convenient annotation, all classes marked by this annotation will be injected into Spring IoC. Here we implement an @xBean tag annotation using a more flexible and convenient annotation:

@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface XBean {
    String description(a) default "";
}
Copy the code

2.3 Implement scanner

The Spring framework provides us with the scanner to register the tag Bean, it is mentioned in section ClassPathBeanDefinitionScanner, we inherit it with a little modification:

public class XBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {
    public XBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
        super(registry, useDefaultFilters);
        super.addIncludeFilter(newAnnotationTypeFilter(XBean.class)); }}Copy the code

Instead of using the default filter, we specify that the scanner scans for beans marked by @xBeans.

2.4 Implement Bean registration machine

Highlight is coming, we need to 2.1 to 2.3 these components of the definition of assembled in ImportBeanDefinitionRegistrar implementation.

/**
 * The type X bean definition registrar.
 *
 * @author felord.cn
 * @since2020/9 / * / space of 18
public class XBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar.ResourceLoaderAware {
    private ResourceLoader resourceLoader;

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // Do not use the default filter
        XBeanDefinitionScanner xBeanDefinitionScanner = new XBeanDefinitionScanner(registry, false);
        xBeanDefinitionScanner.setResourceLoader(resourceLoader);
        // Scan the package specified by the XBeanScan annotation
        xBeanDefinitionScanner.scan(getBasePackagesToScan(importingClassMetadata));
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    /** * get {@linkXBeanScan} specifies the path of the scanned package *@param metadata the meta
     * @returnPackage path array */
    private String[] getBasePackagesToScan(AnnotationMetadata metadata) {
        String name = XBeanScan.class.getName();
        AnnotationAttributes attributes = AnnotationAttributes.fromMap(metadata.getAnnotationAttributes(name, true));
        Assert.notNull(attributes, () -> "No auto-configuration attributes found. Is " + metadata.getClassName()
                + " annotated with " + ClassUtils.getShortName(name) + "?");
        return attributes.getStringArray("basePackages"); }}Copy the code

ImportingClassMetadata parse the required scan path basePackages and other metadata, and then let the scanner scan in that path.

2.5 the use of

Use @xBeanscan on a class with the @Configuration tag or on a Spring Boot Main class.

@ComponentScan provides similar functionality.

3. Summary

This paper is a specific application of the last theory. To be honest, the last one is rather boring and even fails to grasp the key point, but sometimes the theory is like this. Once you read this passage you will see the light. If you need more fine-grained control was combined with those BeanDefinitionRegistryPostProcessor and FactoryBean Spring provides functional interface. What you need to learn more from these two articles is how to use existing components to implement your own logic from reading source code by analogy. This is a huge improvement for you. Well today is here, a lot of attention: code farmers small fat brother more dry goods waiting for you.

Follow our public id: Felordcn for more information

Personal blog: https://felord.cn