深入理解spring注解之@ComponentScan注解


今天主要從以下幾個方面來介紹一下@ComponentScan注解:

  • @ComponentScan注解是什么

  • @ComponentScan注解的詳細使用


1,@ComponentScan注解是什么


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



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注解的注解方式

最后一種方式這邊沒有演示,算留給大家的一個小問題吧,感興趣的同學自己實現下,有疑問也歡迎留言

以上是今天文章的所有內容,歡迎大家吐槽

原文地址:https://blog.51cto.com/4247649/2118342


免責聲明!

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



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