1.@ComponentScan 是什麼
主要就是定義掃描的路徑從中找出標識了需要裝配的類自動裝配到spring的bean容器中。註解定義如下
package org.springframework.context.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AliasFor;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
/**
* 對應的包掃描路徑 可以是單個路徑,也可以是掃描的路徑數組
* @return
*/
@AliasFor("basePackages")
String[] value() default {};
/**
* 和value一樣是對應的包掃描路徑 可以是單個路徑,也可以是掃描的路徑數組
* @return
*/
@AliasFor("value")
String[] basePackages() default {};
/**
* 指定具體的掃描的類
* @return
*/
Class<?>[] basePackageClasses() default {};
/**
* 對應的bean名稱的生成器 默認的是BeanNameGenerator
* @return
*/
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
/**
* 處理檢測到的bean的scope範圍
*/
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
/**
* 是否爲檢測到的組件生成代理
* Indicates whether proxies should be generated for detected components, which may be
* necessary when using scopes in a proxy-style fashion.
* <p>The default is defer to the default behavior of the component scanner used to
* execute the actual scan.
* <p>Note that setting this attribute overrides any value set for {@link #scopeResolver}.
* @see ClassPathBeanDefinitionScanner#setScopedProxyMode(ScopedProxyMode)
*/
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
/**
* 控制符合組件檢測條件的類文件 默認是包掃描下的 **/*.class
* @return
*/
String resourcePattern() default "**/*.class";
/**
* 是否對帶有@Component @Repository @Service @Controller註解的類開啓檢測,默認是開啓的
* @return
*/
boolean useDefaultFilters() default true;
/**
* 指定某些定義Filter滿足條件的組件 FilterType有5種類型如:
* ANNOTATION, 註解類型 默認
ASSIGNABLE_TYPE,指定固定類
ASPECTJ, ASPECTJ類型
REGEX,正則表達式
CUSTOM,自定義類型
* @return
*/
ComponentScan.Filter[] includeFilters() default {};
/**
* 排除某些過濾器掃描到的類
* @return
*/
ComponentScan.Filter[] excludeFilters() default {};
/**
* 掃描到的類是都開啓懶加載 ,默認是不開啓的
* @return
*/
boolean lazyInit() default false;
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Filter {
FilterType type() default FilterType.ANNOTATION;
@AliasFor("classes")
Class<?>[] value() default {};
@AliasFor("value")
Class<?>[] classes() default {};
String[] pattern() default {};
}
}
basePackages與value: 用於指定包的路徑,進行掃描
basePackageClasses: 用於指定某個類的包的路徑進行掃描
nameGenerator: bean的名稱的生成器
useDefaultFilters: 是否開啓對@Component,@Repository,@Service,@Controller的類進行檢測
includeFilters: 包含的過濾條件
FilterType.ANNOTATION:按照註解過濾
FilterType.ASSIGNABLE_TYPE:按照給定的類型
FilterType.ASPECTJ:使用ASPECTJ表達式
FilterType.REGEX:正則
FilterType.CUSTOM:自定義規則
excludeFilters: 排除的過濾條件,用法和includeFilters一樣,使用excludeFilters時,useDefaultFilters 要爲true。
2.@ComponentScan註解的詳細使用
做過web開發的同學一定都有用過@Controller,@Service,@Repository註解,查看其源碼你會發現,他們中有一個共同的註解@Component,沒錯@ComponentScan註解默認就會裝配標識了@Controller,@Service,@Repository,@Component註解的類到spring容器中,好下面咱們就先來簡單演示一下這個例子
分別創建帶註解的service,dao,controller類,目錄如下
Controller帶@Controller
Service帶@Service
Dao帶@Repository
再建一個配置類MainConfig
//配置類 == 配置文件xml
@Configuration
@ComponentScan(value = "com.enjoy.cap2")
public class MainConfig {
//給aop容器註冊一個bean,類型爲返回值類型,默認bean id 是方法名,可以自定義
@Bean
public Person person(){
return new Person("JJJ",12);
}
}
測試類
測試一:默認攔截規則
@Test
public void test01(){
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
String[] names = applicationContext.getBeanDefinitionNames();
//System.out.println(names);
for (String name : names) {
System.out.println(name);
}
}`
測試結果:
把所有帶註解的bean都註冊進去了
測試二:includeFilters 修改Mainconfig如下,使用註解攔截器。過濾類型是ANNOTATION(註解),只過濾controller,關閉默認的過濾器
//配置類 == 配置文件xml
@Configuration
@ComponentScan(value = "com.enjoy.cap2",includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
},useDefaultFilters = false)
public class MainConfig {
//給aop容器註冊一個bean,類型爲返回值類型,默認bean id 是方法名,可以自定義
@Bean
public Person person(){
return new Person("JJJ",12);
}
}
運行測試類,測試結果:
除了自己本身和自定義的bean之外,系統只注入了controller
測試三:excludeFilters 修改Mainconfig如下,使用註解攔截器。過濾類型是ANNOTATION(註解),排除controller,開啓默認的過濾器
//配置類 == 配置文件xml
@Configuration
@ComponentScan(value = "com.enjoy.cap2",excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
},useDefaultFilters = true)
public class MainConfig {
//給aop容器註冊一個bean,類型爲返回值類型,默認bean id 是方法名,可以自定義
@Bean
public Person person(){
return new Person("JJJ",12);
}
}
測試結果:沒有註冊controller類
測試四:過濾方式爲 ASSIGNABLE_TYPE,指定過濾類型,配置類如下
//配置類 == 配置文件xml
@Configuration
@ComponentScan(value = "com.enjoy.cap2",includeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {OrderController.class})
},useDefaultFilters = false)
public class MainConfig {
//給aop容器註冊一個bean,類型爲返回值類型,默認bean id 是方法名,可以自定義
@Bean
public Person person(){
return new Person("JJJ",12);
}
}
測試結果:只有指定的orderController類被註冊進容器
測試五:自定義過濾方式
1.新建一個CustomTypeFilter類實現TypeFilter接口,並實現其 match 方法。
public class CustomTypeFilter implements TypeFilter {
/**
*
* @param metadataReader:讀取到當前正在掃描類的信息
* @param metadataReaderFactory:可以獲取到其任何類信息
* @return
* @throws IOException
*/
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
//獲取當前掃描到的類的註解元數據(信息)
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
//獲取當前掃描到的類的元數據(信息)
ClassMetadata classMetadata = metadataReader.getClassMetadata();
//獲取當前掃描到的類的資源信息(路徑)
Resource resource = metadataReader.getResource();
String className = classMetadata.getClassName();
System.out.println("========>"+className);
if(className.contains("con")){ //當類包含con字符串,匹配成功,返回true
return true;
}
return false;
}
這裏簡單對掃描到的類名進行判斷,如果類名包含”con“的就符合條件,也就會注入到容器中。
2.修改配置類:type = FilterType.CUSTOM, classes = {CustomTypeFilter.class}
//配置類 == 配置文件xml
@Configuration
@ComponentScan(value = "com.enjoy.cap2",includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {CustomTypeFilter.class})
},useDefaultFilters = false)
public class MainConfig {
//給aop容器註冊一個bean,類型爲返回值類型,默認bean id 是方法名,可以自定義
@Bean
public Person person(){
return new Person("JJJ",12);
}
}
測試結果: