使用Spring Boot进行组件扫描 -reflectoring


在本文中,我们将研究Spring组件扫描及其使用方法。本文中的所有示例都将使用Spring Boot应用程序。
为了进行依赖注入,Spring创建了一个所谓的应用程序上下文。
在启动期间,Spring实例化对象并将其添加到应用程序上下文中。应用程序上下文中的对象称为“ Spring bean”或“ components”。
Spring解析Spring bean之间的依赖关系,并将Spring bean注入其他Spring bean的字段或构造函数中。
在类路径中搜索应有助于应用程序上下文的类的过程称为组件扫描。
 
如果Spring找到一个用多个注释之一注释的类,它将在组件扫描期间将该类视为将Spring Bean添加到应用程序上下文的候选对象。
Spring组件主要由四种类型组成。

  • @Component: 这是一个通用的构造型注释,用于指示该类是Spring托管的组件。其他刻板印象是的专业化@Component。
  • @Controller: 这表明带注释的类是Spring托管的控制器,它提供带注释的方法@RequestMapping来回答Web请求。4.0推出了@RestController它结合了注释@Controller和@ResponseBody:可轻松创建基于REST的服务回报JSON对象。
  • @Service:对于包含业务逻辑的类或服务层中的类,我们可以使用构造型。
  • @Repository:我们可以@Repository对DAO类使用构造型,该类负责提供对数据库实体的访问。如果我们使用Spring Data来管理数据库操作,则应该使用Spring Data Repository接口,而不是构建自己的带@Repository注释的类。

 
Spring提供了一种通过@ComponentScan注释显式标识Spring bean候选对象的机制。
如果该应用程序是Spring Boot应用程序,则包含Spring Boot应用程序类的软件包下的所有软件包都将被隐式组件扫描覆盖。
SpringBoot的@SpringBootApplication注解意味着@Configuration,@ComponentScan和@EnableAutoConfiguration三个注释之和。
  • 默认情况下,@ComponentScan注释将扫描当前包及其所有子包中的组件。因此,如果您的应用程序没有变化的包结构,那么就不需要显式的组件扫描。
  • @Configuration在默认包中指定-annotated类将告诉Spring扫描类路径中所有JARS中的所有类。不要那样做!

 
获得@ComponentScan所有列表:
@Component
class BeanViewer {

  private final Logger LOG = LoggerFactory.getLogger(getClass());

  @EventListener
  public void showBeansRegistered(ApplicationReadyEvent event) {
    String[] beanNames = event.getApplicationContext()
      .getBeanDefinitionNames();

      for(String beanName: beanNames) {
        LOG.info("{}", beanName);
      }
  }
}

上面BeanViewer将打印所有在应用程序上下文中注册的bean。这将帮助我们检查组件是否正确加载。
 
Spring Boot会自动扫描父包下的所有包。如果我们有一个不在父软件包下的软件包,或者根本没有使用Spring Boot,那么我们可以将其@ComponentScan与@Configurationbean一起使用。下面将告诉Spring扫描此类的包@Configuration及其子包中的组件:

package io.reflectoring.birds;

@Configuration
@ComponentScan
public class BirdsExplicitScan {
}

birds软件包位于应用程序的主软件包旁边,因此它不会被Spring Boot的默认扫描捕获。
 
@ComponentScan与属性
让我们看一下@ComponentScan可用于修改其行为的注释的属性:

  • basePackages:获取应扫描的组件名称的列表。
  • basePackageClasses:获取应扫描其软件包的类的列表。
  • includeFilters:使我们能够指定应扫描的组件类型。
  • excludeFilters:这与的相反includeFilters。我们可以指定条件以在扫描时根据条件忽略某些组件。
  • useDefaultFilters:如果为true,则启用对带有任何构造型注释的类的自动检测。如果为false,则将包含属于includeFilters和定义的过滤条件的组件excludeFilters。

includeFilters/excludeFilters过滤器类型有:

  • ANNOTATION:仅匹配具有特定构造型注释的类。
  • ASPECTJ:使用AspectJ类型模式表达式匹配类
  • ASSIGNABLE_TYPE:匹配扩展或实现此类或接口的类。
  • REGEX:使用包名称的正则表达式匹配类。

@Configuration
@ComponentScan(basePackages= "io.reflectoring.vehicles",
  includeFilters=
    @ComponentScan.Filter(
      type=FilterType.ASSIGNABLE_TYPE,
      classes=Car.class),
    useDefaultFilters=false)
public class ExplicitScan {
}

 
@ComponentScan广泛使用注释会很快导致有关应用程序组成的规则混乱!尽量少使用它,以使您的应用程序上下文规则尽可能明确。
一个好的做法是显式导入@Configuration带有@Import注释的类,并将注释添加@ComponentScan到该配置类中,以仅自动扫描该类的包。这样,我们在应用程序的包之间就具有清晰的边界