摘要:
在平常的開發中,不知道大家有沒有想過這樣一個問題,為什么我們自定義注解的時候要使用spring的原生注解(這里指的是類似@Component
,@Service
........),要么就是 隨便弄個注解,搭配自己的切面編程來實現某些業務邏輯。這篇文章主要給大家分享一下,如何脫離Spring原生注解
自定義注解注入IOC
SpringBootApplication注解分析
從源代碼很容易看出來,它的作用就是自動裝配和掃描我們的包,並將符合的類進行注冊到容器。自動裝配非常簡單,這里不做過多分析,接下來分析一下什么叫做符合規則的類
。在@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;
}
}
以上代碼是正常邏輯,反過來這樣想,如果將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 {
}
透過現象看本質
流程進行梳理一下,注解驅動在注入容器的關鍵掃描類(注意這里是指的掃描,而不是什么@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
來將自己的定義規則的注解進行注入容器。