Spring注解(二):@ComponentScan自动扫描组件

简介: 前一篇文章:Spring注解(一):@Configuration、@Bean给容器中注册组件,提到了如何通过使用配置文件的方式和注解的方式进行简单的组件注册。这里将介绍如何使用@ComponentScan注解进行组件的自动扫描。

前一篇文章:Spring注解(一):@Configuration、@Bean给容器中注册组件,提到了如何通过使用配置文件的方式和注解的方式进行简单的组件注册。这里将介绍如何使用@ComponentScan注解进行组件的自动扫描。


在上一篇代码的基础之上,如果通过配置文件的方式进行组件扫描,则需要在配置文件中使用context:component-scan标签元素,beans.xml文件如下:


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:aop="http://www.springframework.org/schema/aop"
  xmlns:tx="http://www.springframework.org/schema/tx"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
   <!--  包扫描,只要注解了@controller @service @Repository @component四个注解中的任何一个注解的组件都会被扫描加载到容器中-->
   <context:component-scan base-package="com.xinyi"></context:component-scan>
     <bean id="Person" class="com.xinyi.bean.Person">
         <property name="name" value="新一"></property>
         <property name="age" value="18"></property>
     </bean> 
</beans>
复制代码


如果采用注解的方式进行组件扫描,则需要在配置类中添加一个@ComponentScan组件:


package com.xinyi.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.xinyi.bean.Person;
//配置类等同于以前的配置文件
//@Configuration等同于告诉spring这是一个配置类
@Configuration
//value指定要扫描的包,默认是该包下组件的都会被扫描
@ComponentScan(value="com.xinyi")
public class MyConfig {
  //@Bean给容器中注入一个bean,类型为返回值得类型,id默认方法名作为id
  //注入person得值
  @Bean("person222")
  public Person person111() {
    return new Person("xinyi、",19);
  }
}
复制代码


然后新建一个controller,service和dao:


package com.xinyi.controller;
import org.springframework.stereotype.Controller;
//被@Controller标记的类实际上就是个Controller对象(即控制器类),分发
//处理器会扫描使用该注解的类的方法,并检测该方法是否使用了@RequestMapping注解。
//@Controller只是定义了一个控制器类,而使用@RequestMapping注解的方法才是处理请求的处理器。
@Controller
public class MyController {
}
复制代码


package com.xinyi.service;
import org.springframework.stereotype.Service;
//@Service注解表示该类是业务层,
@Service
public class MyService {
}
复制代码


package com.xinyi.dao;
import org.springframework.stereotype.Repository;
//@Repository注解修饰哪个类,表示该类属于dao层,具有进行CRUD的功能
@Repository
public class MyDao {
}
复制代码


新建一个测试类,输出扫描的组件有哪些:


package com.xinyi.test;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.xinyi.config.MyConfig;
public class Test {
  @Test
  public void test1() {
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
    String[] strings = applicationContext.getBeanDefinitionNames();
    for(String string : strings) {
      System.out.println(string);
    }
  }
}
复制代码


则被输出的组件有:


myConfig
myController
myDao
myService
person222
复制代码


另外@ComponentScan注解的includeFilters和ExcludeFilters属性能够指定扫描的组件和排除指定不扫描的组件,

includeFilters和excludeFilters属性接受的参数都是数组的形式。


/**
   * Specifies which types are eligible for component scanning.
   * <p>Further narrows the set of candidate components from everything in {@link #basePackages}
   * to everything in the base packages that matches the given filter or filters.
   * <p>Note that these filters will be applied in addition to the default filters, if specified.
   * Any type under the specified base packages which matches a given filter will be included,
   * even if it does not match the default filters (i.e. is not annotated with {@code @Component}).
   * @see #resourcePattern()
   * @see #useDefaultFilters()
   */
  Filter[] includeFilters() default {};
  /**
   * Specifies which types are not eligible for component scanning.
   * @see #resourcePattern
   */
  Filter[] excludeFilters() default {};
复制代码


ExcludeFilters指定不扫描的组件:


package com.xinyi.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import com.xinyi.bean.Person;
//excludeFilters:指定不扫描的组件 这里是按照注解的方式排除Service和Repository
@ComponentScan(value="com.xinyi",excludeFilters = {@Filter(type=FilterType.ANNOTATION,classes = {Service.class,Repository.class})})
public class MyConfig {
  //@Bean给容器中注入一个bean,类型为返回值得类型,id默认方法名作为id
  //注入person得值
  @Bean("person222")
  public Person person111() {
    return new Person("xinyi、",19);
  }
}
复制代码


输出的结果:


//排除了dao和service
myConfig
myController
person222
复制代码


IncludeFilters指定扫描的组件,includeFilters属性有个参数为useDefaultFilters,默认为true,表示默认扫描所有的包,所以如果添加过滤规则扫描指定的组件,则需要将useDefaultFilters=false:


package com.xinyi.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import com.xinyi.bean.Person;
@ComponentScan(value="com.xinyi",includeFilters = {@Filter(type=FilterType.ANNOTATION,classes = {Service.class,Repository.class})},useDefaultFilters = false)
public class MyConfig {
  //@Bean给容器中注入一个bean,类型为返回值的类型,id默认方法名作为id
  //注入person得值
  @Bean("person222")
  public Person person111() {
    return new Person("xinyi、",19);
  }
}
复制代码


输出的组件为:


//只包好了service和dao,并没有扫描到controller
myConfig
myDao
myService
person222
复制代码


在定义包扫描规则中,通过使用@Filter注解的方式指定过滤规则,上述代码是按照注解的方式进行过滤,FilterType是一个枚举类,定义了各种过滤类型:


public enum FilterType {
  /**
   * Filter candidates marked with a given annotation.
   * @see org.springframework.core.type.filter.AnnotationTypeFilter
   */
   //按照注解的方式
  ANNOTATION,
  /**
   * Filter candidates assignable to a given type.
   * @see org.springframework.core.type.filter.AssignableTypeFilter
   */
   //按照给定的类型
  ASSIGNABLE_TYPE,
  /**
   * Filter candidates matching a given AspectJ type pattern expression.
   * @see org.springframework.core.type.filter.AspectJTypeFilter
   */
     //按照ASPECTJ表达式
  ASPECTJ,
  /**
   * Filter candidates matching a given regex pattern.
   * @see org.springframework.core.type.filter.RegexPatternTypeFilter
   */
    //按照正则表达式
  REGEX,
  /** Filter candidates using a given custom
   * {@link org.springframework.core.type.filter.TypeFilter} implementation.
   */
    //按照自定义规则
  CUSTOM
}
复制代码


以上各种过滤类型的使用方法和注解类型使用方式一样,使用较多的是按照指定类型和自定义规则进行过滤,比如:


1、根据指定的类型过滤:


@ComponentScan(value="com.xinyi",includeFilters = {@Filter(type=FilterType.ASSIGNABLE_TYPE,classes = {MyDao.class})},useDefaultFilters = false)
复制代码


2、根据自定义的规则过滤:


首先需要新建一个自定义过滤规则:


package com.xinyi.config;
import java.io.IOException;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
//实现TypeFilter接口
public class MyTypeFilter implements TypeFilter {
  //metadataReader:读取到当前正在扫描的类
  //metadataReaderFactory:读取到其他任何类的信息
  //match方法返回boolean类型的值,true表示匹配,符合过滤规则,false则不匹配
  public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
      throws IOException {
    // TODO Auto-generated method stub
    //获取当前类注解的信息
    AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
    //获取正在扫描的类的信息
    ClassMetadata classMetadata = metadataReader.getClassMetadata();
    //获取当前类资源信息(路径信息)
    Resource resource = metadataReader.getResource();
    String classnameString = classMetadata.getClassName();
    System.out.println("正在扫描的类:"+classnameString);
    if(classnameString.contains("er")) {
      return true;
    }
    return false;
  }
}
复制代码


使用自定义过滤规则:


@ComponentScan(value="com.xinyi",includeFilters = {@Filter(type=FilterType.CUSTOM,classes = {MyTypeFilter.class})},useDefaultFilters = false)
复制代码


输出结果:


8e6cd168727240189d2d1675093fe1f9~tplv-k3u1fbpfcp-zoom-in-crop-mark_1304_0_0_0.webp.jpg


@ComponentScans注解,等同于多个@ComponentScan注解(在一个类中可以同时写多个@ComponentScan注解,定义多种包扫描过滤规则),所以如果定义多种组件扫描的过滤规则,可以使用@ComponentScans注解:


@ComponentScans(value = {
@ComponentScan(value="com.xinyi",includeFilters = {@Filter(type=FilterType.ANNOTATION,classes = {Service.class,Repository.class})},useDefaultFilters = false),... })
复制代码


以上就是注解开发中如何使用@ComponentScan注解进行包扫描,以及使用IncludeFilters和ExcludeFilters属性,定义包扫描过滤规则。

目录
相关文章
|
1月前
|
XML Java 测试技术
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
121 26
|
2月前
|
缓存 Java 数据库
SpringBoot缓存注解使用
Spring Boot 提供了一套方便的缓存注解,用于简化缓存管理。通过 `@Cacheable`、`@CachePut`、`@CacheEvict` 和 `@Caching` 等注解,开发者可以轻松地实现方法级别的缓存操作,从而提升应用的性能和响应速度。合理使用这些注解可以大大减少数据库的访问频率,优化系统性能。
186 89
|
18天前
|
监控 Java Spring
SpringBoot:SpringBoot通过注解监测Controller接口
本文详细介绍了如何通过Spring Boot注解监测Controller接口,包括自定义注解、AOP切面的创建和使用以及具体的示例代码。通过这种方式,可以方便地在Controller方法执行前后添加日志记录、性能监控和异常处理逻辑,而无需修改方法本身的代码。这种方法不仅提高了代码的可维护性,还增强了系统的监控能力。希望本文能帮助您更好地理解和应用Spring Boot中的注解监测技术。
53 16
|
3月前
|
Java Spring 容器
【SpringFramework】Spring IoC-基于注解的实现
本文主要记录基于Spring注解实现IoC容器和DI相关知识。
67 21
|
8天前
|
Java 数据库 开发者
详细介绍SpringBoot启动流程及配置类解析原理
通过对 Spring Boot 启动流程及配置类解析原理的深入分析,我们可以看到 Spring Boot 在启动时的灵活性和可扩展性。理解这些机制不仅有助于开发者更好地使用 Spring Boot 进行应用开发,还能够在面对问题时,迅速定位和解决问题。希望本文能为您在 Spring Boot 开发过程中提供有效的指导和帮助。
46 12
|
11天前
|
Java 应用服务中间件 Maven
SpringBoot项目打包成war包
通过上述步骤,我们成功地将一个Spring Boot应用打包成WAR文件,并部署到外部的Tomcat服务器中。这种方式适用于需要与传统Servlet容器集成的场景。
30 8
|
2月前
|
XML Java 应用服务中间件
Spring Boot 两种部署到服务器的方式
本文介绍了Spring Boot项目的两种部署方式:jar包和war包。Jar包方式使用内置Tomcat,只需配置JDK 1.8及以上环境,通过`nohup java -jar`命令后台运行,并开放服务器端口即可访问。War包则需将项目打包后放入外部Tomcat的webapps目录,修改启动类继承`SpringBootServletInitializer`并调整pom.xml中的打包类型为war,最后启动Tomcat访问应用。两者各有优劣,jar包更简单便捷,而war包适合传统部署场景。需要注意的是,war包部署时,内置Tomcat的端口配置不会生效。
308 17
Spring Boot 两种部署到服务器的方式
|
2月前
|
Dart 前端开发 JavaScript
springboot自动配置原理
Spring Boot 自动配置原理:通过 `@EnableAutoConfiguration` 开启自动配置,扫描 `META-INF/spring.factories` 下的配置类,省去手动编写配置文件。使用 `@ConditionalXXX` 注解判断配置类是否生效,导入对应的 starter 后自动配置生效。通过 `@EnableConfigurationProperties` 加载配置属性,默认值与配置文件中的值结合使用。总结来说,Spring Boot 通过这些机制简化了开发配置流程,提升了开发效率。
78 17
springboot自动配置原理
|
2月前
|
XML JavaScript Java
SpringBoot集成Shiro权限+Jwt认证
本文主要描述如何快速基于SpringBoot 2.5.X版本集成Shiro+JWT框架,让大家快速实现无状态登陆和接口权限认证主体框架,具体业务细节未实现,大家按照实际项目补充。
103 11
|
2月前
|
缓存 安全 Java
Spring Boot 3 集成 Spring Security + JWT
本文详细介绍了如何使用Spring Boot 3和Spring Security集成JWT,实现前后端分离的安全认证概述了从入门到引入数据库,再到使用JWT的完整流程。列举了项目中用到的关键依赖,如MyBatis-Plus、Hutool等。简要提及了系统配置表、部门表、字典表等表结构。使用Hutool-jwt工具类进行JWT校验。配置忽略路径、禁用CSRF、添加JWT校验过滤器等。实现登录接口,返回token等信息。
503 12