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

項目環境搭建
- 建立Maven子工程
,并在子工程的pom.xml檔案中導入spring-context等依賴demo-two
<?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 {}
- @Filter注解的type屬性可以指定5種類型