天天看點

Spring注解驅動開發(二)之@ComponentScans、@ComponentScan和@Filter注解

除了可以通過@Bean注解的方式為IoC容器注冊元件,也可以通過包掃描(@ComponentScan注解)的方式為IoC容器注冊元件

項目目錄結構

Spring注解驅動開發(二)之@ComponentScans、@ComponentScan和@Filter注解

項目環境搭建

  • 建立Maven子工程

    demo-two

    ,并在子工程的pom.xml檔案中導入spring-context等依賴
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>spring-annotation</artifactId>
        <groupId>com.codermyu</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>demo-two</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
    </dependencies>


</project>
           
  • 在controller包下建立UserController類
package com.codermyu.controller;

import org.springframework.stereotype.Controller;

/** @author Mingyu */
@Controller
public class UserController {}
           
  • 在service包下建立UserService類
package com.codermyu.service;

import org.springframework.stereotype.Service;

/** @author Mingyu */
@Service
public class UserService {}
           
  • 在dao包下建立UserDao類
package com.codermyu.dao;

import org.springframework.stereotype.Repository;

/** @author Mingyu */
@Repository
public class UserDao {}
           
  • 在config包下建立配置類MySpringConfig
package com.codermyu.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/** @author Mingyu */
@ComponentScan(basePackages = {"com.codermyu"})
@Configuration
public class MySpringConfig {}
           
  • 建立啟動類App
package com.codermyu;

import com.codermyu.config.MySpringConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/** @author Mingyu */
public class App {
  public static void main(String[] args) {
    ApplicationContext applicationContext =
        new AnnotationConfigApplicationContext(MySpringConfig.class);
    String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
      System.out.println(beanDefinitionName);
    }
  }
}
           

細節

  • @ComponentScan注解
    • @ComponentScan注解需要标注在配置類上
    • 為@ComponentScan注解添加basePackages屬性,可以指定包掃描時的根路徑,IoC容器在啟動時會掃描該路徑下所有标注了@Configuration、@Component、@Controller、@Service、@Repository注解的類并建立元件,然後将建立的元件注冊到IoC容器中
    • 建立的元件的id為類名的首字母小寫(預設),為@Configuration、@Component、@Controller、@Service、@Repository注解添加value屬性,可以重新指定元件的id,而不使用預設的首字母小寫作為元件的id
      • @Controller(value = "userControllerSpecified")

    • 為@ComponentScan注解添加excludeFilters屬性,可以指定包掃描時的排除規則(不掃描哪些元件)
      package com.codermyu.config;
      
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.context.annotation.FilterType;
      import org.springframework.stereotype.Controller;
      import org.springframework.stereotype.Service;
      
      /** @author Mingyu */
      @ComponentScan(
          basePackages = {"com.codermyu"},
          excludeFilters = {
            @ComponentScan.Filter(
                /** 包掃描時不掃描标注了@Controller注解和@Service注解的類 */
                type = FilterType.ANNOTATION,
                classes = {Controller.class, Service.class})
          })
      @Configuration
      public class MySpringConfig {}
                 
    • 為@ComponentScan注解添加includeFilters屬性,可以指定包掃描時的包含規則(額外掃描哪些元件)
      • 包掃描時如果希望隻掃描某些特定元件,需要禁用預設的過濾器
      package com.codermyu.config;
      
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.context.annotation.FilterType;
      import org.springframework.stereotype.Controller;
      import org.springframework.stereotype.Repository;
      
      /** @author Mingyu */
      @ComponentScan(
          basePackages = {"com.codermyu"},
          /** 禁用預設的過濾器 */
          useDefaultFilters = false,
          includeFilters = {
            @ComponentScan.Filter(
                /** 包掃描時隻掃描标注了@Controller注解和@Repository注解的類 */
                type = FilterType.ANNOTATION,
                classes = {Controller.class, Repository.class})
          })
      @Configuration
      public class MySpringConfig {}
                 
  • @ComponentScans注解
    • Java8以及Java8以後的Java版本支援@Repeatable注解,@ComponentScan注解可以在配置類上标注多次,用于指定不同的包掃描政策
    • Java8以前的Java版本,可以采用@ComponentScans注解包含多個@ComponentScan注解的方式,指定不同的包掃描政策
  • @Filter注解
    • @Filter注解的type屬性可以指定5種類型
      • FilterType.ANNOTATION:按照指定的注解規則過濾元件
      • FilterType.ASSIGNABLE_TYPE:按照指定的類型規則過濾元件
      • FilterType.ASPECTJ:按照指定的AspectJ表達式規則過濾元件
      • FilterType.REGEX:按照指定的正規表達式規則過濾元件
      • FilterType.CUSTOM:按照自定義規則過濾元件
      package com.codermyu.config;
      
      import com.codermyu.service.UserService;
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.context.annotation.FilterType;
      import org.springframework.stereotype.Controller;
      
      /** @author Mingyu */
      @ComponentScan(
          basePackages = {"com.codermyu"},
          useDefaultFilters = false,
          includeFilters = {
            @ComponentScan.Filter(
                type = FilterType.ANNOTATION,
                classes = {Controller.class}),
            @ComponentScan.Filter(
                type = FilterType.ASSIGNABLE_TYPE,
                classes = {UserService.class})
          })
      @Configuration
      public class MySpringConfig {}
                 
    • 自定義Filter
      • 在filter包下建立MyFilter類,該類需要實作TypeFilter接口,并重寫match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)方法
      • metadataReader
        • 用來擷取目前正在掃描的類的資訊
        • metadataReader.getResource():擷取類的資源資訊
        • metadataReader.getClassMetadata():擷取類的類資訊
        • metadataReader.getAnnotationMetadata():擷取類的注解資訊
      • metadataReaderFactory
        • 用來擷取其他類的metadataReader,然後通過metadataReader擷取類的資訊
        • metadataReaderFactory.getMetadataReader(String className):通過類名擷取metadataReader
      package com.codermyu.filter;
      
      import org.springframework.core.type.AnnotationMetadata;
      import org.springframework.core.type.classreading.MetadataReader;
      import org.springframework.core.type.classreading.MetadataReaderFactory;
      import org.springframework.core.type.filter.TypeFilter;
      import org.springframework.stereotype.Controller;
      
      import java.io.IOException;
      
      /** @author Mingyu */
      public class MyFilter implements TypeFilter {
        @Override
        public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
            throws IOException {
          /** 通過metadataReader擷取目前正在掃描的類的注解資訊 */
          AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
          /** 如果目前正在掃描的類标注了@Controller注解,match方法就傳回true,否則傳回false */
          return annotationMetadata.hasAnnotation(Controller.class.getName());
        }
      }
                 
      • 将自定義Filter添加到Filter組中
        • basePackages指定的路徑下的每個類都會通過MyFilter類中的match()方法進行過濾,如果比對成功,就将目前正在掃描的類注冊到IoC容器中
      package com.codermyu.config;
      
      import com.codermyu.filter.MyFilter;
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.context.annotation.FilterType;
      
      /** @author Mingyu */
      @ComponentScan(
          basePackages = {"com.codermyu"},
          useDefaultFilters = false,
          includeFilters = {
            @ComponentScan.Filter(
                type = FilterType.CUSTOM,
                classes = {MyFilter.class})
          })
      @Configuration
      public class MySpringConfig {}
                 

繼續閱讀