深入理解spring註解之@ComponentScan註解
深入理解spring註解之@ComponentScan註解
知了123 0人評論 149062人閱讀 2018-05-20 10:02:23今天主要從以下幾個方面來介紹一下@ComponentScan註解:
@ComponentScan註解是什麼
@ComponentScan註解的詳細使用
1,@ComponentScan註解是什麼
其實很簡單,@ComponentScan主要就是定義
2,@ComponentScan註解的詳細使用
做過web開發的同學一定都有用過@Controller,@Service,@Repository註解,檢視其原始碼你會發現,他們中有一個共同的註解@Component,沒錯@ComponentScan註解預設就會裝配標識了@Controller,@Service,@Repository,@Component註解的類到spring容器中,好下面咱們就先來簡單演示一下這個例子
在包com.zhang.controller下新建一個UserController帶@Controller註解如下:
package com.zhang.controller;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
}
在包com.zhang.service下新建一個UserService帶@Service註解如下:
package com.zhang.service;
import org.springframework.stereotype.Service ;
@Service
public class UserService {
}
在包com.zhang.dao下新建一個UserDao帶@Repository註解如下:
package com.zhang.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
}
新建一個配置類如下:
/**
* 主配置類 包掃描com.zhang
*
* @author zhangqh
* @date 2018年5月12日
*/
@ComponentScan(value="com.zhang")
@Configuration
public class MainScanConfig {
}
新建測試方法如下:
AnnotationConfigApplicationContext applicationContext2 = new AnnotationConfigApplicationContext(MainScanConfig.class);
String[] definitionNames = applicationContext2.getBeanDefinitionNames();
for (String name : definitionNames) {
System.out.println(name);
}
執行結果如下:
mainScanConfig
userController
userDao
userService
怎麼樣,包掃描的方式比以前介紹的通過@Bean註解的方式是不是方便很多,這也就是為什麼web開發的同學經常使用此方式的原因了
上面只是簡單的介紹了@ComponentScan註解檢測包含指定註解的自動裝配,接下來讓我們來看看@ComponentScan註解的更加詳細的配置,在演示詳細的配置之前,讓我們先看看@ComponentScan的原始碼如下:
@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 ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
/**
* 是否對帶有@Component @Repository @Service @Controller註解的類開啟檢測,預設是開啟的
* @return
*/
boolean useDefaultFilters() default true;
/**
* 指定某些定義Filter滿足條件的元件 FilterType有5種類型如:
* ANNOTATION, 註解型別 預設
ASSIGNABLE_TYPE,指定固定類
ASPECTJ, ASPECTJ型別
REGEX,正則表示式
CUSTOM,自定義型別
* @return
*/
Filter[] includeFilters() default {};
/**
* 排除某些過來器掃描到的類
* @return
*/
Filter[] excludeFilters() default {};
/**
* 掃描到的類是都開啟懶載入 ,預設是不開啟的
* @return
*/
boolean lazyInit() default false;
}
a,演示basePackageClasses引數,如我們把配置檔案改成如下:
@ComponentScan(value="com.zhang.dao",useDefaultFilters=true,basePackageClasses=UserService.class)
@Configuration
public class MainScanConfig {
}
測試結果如下:
mainScanConfig
userDao
userService
只有userDao外加basePackageClasses指定的userService加入到了spring容器中
b,演示includeFilters引數的使用如下:
在com.zhang.service包下新建一個UserService2類如下:注意沒有帶@Service註解
package com.zhang.service;
public class UserService2 {
}
配置類改成:
@ComponentScan(value="com.zhang",useDefaultFilters=true,
includeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={UserService2.class})
})
@Configuration
public class MainScanConfig {
}
執行結果如下:
mainScanConfig
userController
userDao
userService
userService2
userService2同樣被加入到了spring容器
新增一個自定義的實現了TypeFilter的MyTypeFilter類如下:
/**
* 自定義過濾
*
* @author zhangqh
* @date 2018年5月12日
*/
public class MyTypeFilter implements TypeFilter {
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);
// 檢測名字包含Service的bean
if(className.contains("Service")){
return true;
}
return false;
}
}
修改主配置如下:
@ComponentScan(value="com.zhang",useDefaultFilters=true,
includeFilters={
@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
})
@Configuration
public class MainScanConfig {
}
執行結果如下:
mainScanConfig
userController
userDao
userService
userService2
可以發現同樣userService2被加入到了spring容器中
好了includeFilters引數就演示到這,另外一個引數excludeFilters和includeFilters使用者一摸一樣,只是他是過濾出不加入spring容器中,感興趣的同學可以自己試試,我這邊就不演示了
總結一下@ComponentScan的常用方式如下
自定掃描路徑下邊帶有@Controller,@Service,@Repository,@Component註解加入spring容器
通過includeFilters加入掃描路徑下沒有以上註解的類加入spring容器
通過excludeFilters過濾出不用加入spring容器的類
自定義增加了@Component註解的註解方式
最後一種方式這邊沒有演示,算留給大家的一個小問題吧,感興趣的同學自己實現下,有疑問也歡迎留言
以上是今天文章的所有內容,歡迎大家吐槽
推薦閱讀
深入理解spring生命週期與BeanPostProcessor的實現原理
更多優質文章請關注以下公眾號查閱:
0
微博 QQ 微信收藏
上一篇:三分鐘學會@[email protected] 下一篇:深入理解spring註解@Pro... 知了123