深刻理解spring註解之@ComponentScan註解

今天主要從如下幾個方面來介紹一下@ComponentScan註解:web

  • @ComponentScan註解是什麼正則表達式

  • @ComponentScan註解的詳細使用spring


1,@ComponentScan註解是什麼數組


其實很簡單,@ComponentScan主要就是定義掃描的路徑從中找出標識了須要裝配的類自動裝配到spring的bean容器中app



2,@ComponentScan註解的詳細使用ide


作過web開發的同窗必定都有用過@Controller,@Service,@Repository註解,查看其源碼你會發現,他們中有一個共同的註解@Component,沒錯@ComponentScan註解默認就會裝配標識了@Controller,@Service,@Repository,@Component註解的類到spring容器中,好下面我們就先來簡單演示一下這個例子測試


在包com.zhang.controller下新建一個UserController帶@Controller註解以下:this


package com.zhang.controller;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
}


在包com.zhang.service下新建一個UserService帶@Service註解以下:spa


package com.zhang.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
}


在包com.zhang.dao下新建一個UserDao帶@Repository註解以下:3d


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的實現原理

250G偷懶必看資料全集


更多優質文章請關注如下公衆號查閱:


相關文章
相關標籤/搜索