Springboot源碼分析之TypeFilter魔力


摘要:

在平常的開發中,不知道大家有沒有想過這樣一個問題,為什么我們自定義注解的時候要使用spring的原生注解(這里指的是類似@Component@Service........),要么就是 隨便弄個注解,搭配自己的切面編程來實現某些業務邏輯。這篇文章主要給大家分享一下,如何脫離Spring原生注解自定義注解注入IOC

SpringBootApplication注解分析

file
從源代碼很容易看出來,它的作用就是自動裝配和掃描我們的包,並將符合的類進行注冊到容器。自動裝配非常簡單,這里不做過多分析,接下來分析一下什么叫做符合規則的類。在@ComponentScan注解上面的過濾器類型的定義

public enum FilterType {
    ANNOTATION, //注解類型
    ASSIGNABLE_TYPE, //指定的類型
    ASPECTJ, //按照Aspectj的表達式,基本上不會用到
    REGEX, //按照正則表達式
    CUSTOM; //自定義

    private FilterType() {
    }
}

excludeFilters排除過濾器

這個是給我們排除符合的類,不讓他注冊到IOC的時候使用的, Springboot默認使用兩個排除過濾器,很簡單的,網上隨便搜都可以找到相關說明,在這兒我舉個特舒列子就行了.

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;
    }
}

file
以上代碼是正常邏輯,反過來這樣想,如果將Tt類的@Component注解去掉是不是也行的,所以這種排除注解一般都用在正常可以注入到容器的時候進行添加的,那么我們上面說過,脫離Spring也可以注入到容器,該怎么實現呢?

includeFilters包含過濾器

脫離Spring原生注解,將將Tt類的@Component注解去掉

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 {
}

file

透過現象看本質

流程進行梳理一下,注解驅動在注入容器的關鍵掃描類(注意這里是指的掃描,而不是什么@Bean,@Import等其余注解都是建立在這個基礎之上的)

  • 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) {
        }

    }

此處會將@Component,JSR-250 'javax.annotation.ManagedBean' ,JSR-330 'javax.inject.Named' 的注解進行注冊,所以難怪我們的自定義注解必須要有這些派生注解,換一個角度來思考,它們這個地方進行類AnnotationTypeFilter的添加,我們也可以自定義AnnotationTypeFilter來將自己的定義規則的注解進行注入容器。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM