TypeFilter magic of Springboot source analysis

Keywords: Java SpringBoot Spring github

Summary:

In normal development, I don't know if you've ever thought about it. Why do we use spring's native annotations when we customize annotations (in this case, like @Component, @Service.......)), or just make a comment and use your own facet programming to implement some business logic?This article focuses on sharing how to inject IOC out of Spring's native comment custom comment

Annotation Analysis for SpringBootApplication


It is easy to see from the source code that its purpose is to automatically assemble and scan our packages and register the matching classes into containers.Auto-assembly is very simple. Without much analysis here, let's look at what is called a rule-compliant class.Definition of filter type above @ComponentScan annotation

public enum FilterType {
    ANNOTATION, //annotation type
    ASSIGNABLE_TYPE, //Specified Type
    ASPECTJ, //Basically not used, according to Aspectj's expression
    REGEX, //By regular expression
    CUSTOM; //custom

    private FilterType() {
    }
}

excludeFilters Exclude Filters

This is for us to exclude matching classes from being used when registering with IOC. Springboot uses two exclusion filters by default. It's very simple, and you can find instructions by searching the Internet. Here I'll just lift a tesla.

package com.github.dqqzj.springboot.filter;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author qinzhongjian
 * @date created in 2019-07-30 19:14
 * @description: TODO
 * @since JDK 1.8.0_212-b10
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Dqqzj {
    String value();
}
package com.github.dqqzj.springboot.filter;

import org.springframework.stereotype.Component;

/**
 * @author qinzhongjian
 * @date created in 2019-07-29 22:30
 * @description: TODO
 * @since JDK 1.8.0_212-b10
 */
@Dqqzj(value = "dqqzj")
@Component
public class Tt {
}
package com.github.dqqzj.springboot.filter;

import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;

import java.io.IOException;

/**
 * @author qinzhongjian
 * @date created in 2019-07-30 19:13
 * @description: TODO
 * @since JDK 1.8.0_212-b10
 */
public class MyTypeFilter implements TypeFilter {
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        if (metadataReader.getAnnotationMetadata().isAnnotated(Dqqzj.class.getName())) {
            return true;
        }
        return false;
    }
}


The above code is the normal logic. Conversely, if it's okay to remove the @Component comment from the Tt class, so this exclusion comment is usually added when it's normally injectable into containers, what do we do when we said above that you can inject into containers without Spring?

IncudeFilters Contains Filters

Remove the @Component comment for the Tt class from the Spring native comment

package com.github.dqqzj.springboot.filter;

import org.springframework.stereotype.Component;

/**
 * @author qinzhongjian
 * @date created in 2019-07-29 22:30
 * @description: TODO
 * @since JDK 1.8.0_212-b10
 */
@Dqqzj(value = "dqqzj")
//@Component
public class Tt {
}

See essence through phenomenon

The process combs and annotations drive the critical scan classes in the injection container (note that this refers to scans, not what @Bean, @Import, and so on, on which the rest of the annotations are built)

  • ComponentScanAnnotationParser
  • ClassPathBeanDefinitionScanner
  • ClassPathScanningCandidateComponentProvider
ClassPathScanningCandidateComponentProvider#registerDefaultFilters
protected void registerDefaultFilters() {
        this.includeFilters.add(new AnnotationTypeFilter(Component.class));
        ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();

        try {
            this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.annotation.ManagedBean", cl), false));
            this.logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
        } catch (ClassNotFoundException var4) {
        }

        try {
            this.includeFilters.add(new AnnotationTypeFilter(ClassUtils.forName("javax.inject.Named", cl), false));
            this.logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
        } catch (ClassNotFoundException var3) {
        }

    }

Annotations for @Component, JSR-250'javax.annotation.ManagedBean', JSR-330'javax.inject.Named'are registered here, so it's no surprise that our custom annotations have to have these derived annotations, to think about it differently, where they add AnnotationTypeFilter-like annotations, and where we can customize AnnotaTionTypeFilter to inject its own comments defining rules into the container.

Posted by limitedreality on Thu, 12 Sep 2019 21:40:37 -0700