除了可以通过@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种类型