今天主要从以下几个方面来介绍一下@ComponentScan注解:

  • @ComponentScan注解是什么

  • @ComponentScan注解的详细使用

1,@ComponentScan注解是什么


其实很简单,@ComponentScan主要就是定义扫描的路径从中找出标识了需要装配的类自动装配到spring的bean容器中

2,@ComponentScan注解的详细使用


做过web开发的同学一定都有用过@Controller,@Service,@Repository注解,查看其源码你会发现,他们中有一个共同的注解@Component,没错@ComponentScan注解默认就会装配标识了@Controller,@Service,@Repository,@Component注解的类到spring容器中,好下面咱们就先来简单演示一下这个例子

在包com.zhang.controller下新建一个UserController带@Controller注解如下:

package com.zhang.controller;
import org.springframework.stereotype.Controller;
@Controller
public class UserController {
}

在包com.zhang.service下新建一个UserService带@Service注解如下:

package com.zhang.service;
import org.springframework.stereotype.Service;
@Service
public class UserService {
}

在包com.zhang.dao下新建一个UserDao带@Repository注解如下:

package com.zhang.dao;
import org.springframework.stereotype.Repository;
@Repository
public class UserDao {
}

新建一个配置类如下:

/**
* 主配置类  包扫描com.zhang
*
* @author zhangqh
* @date 2018年5月12日
*/
@ComponentScan(value="com.zhang")
@Configuration
public class MainScanConfig {
}

新建测试方法如下:

AnnotationConfigApplicationContext applicationContext2 = new AnnotationConfigApplicationContext(MainScanConfig.class);
       String[] definitionNames = applicationContext2.getBeanDefinitionNames();
       for (String name : definitionNames) {
           System.out.println(name);
}

运行结果如下:

mainScanConfig
userController
userDao
userService

怎么样,包扫描的方式比以前介绍的通过@Bean注解的方式是不是方便很多,这也就是为什么web开发的同学经常使用此方式的原因了

上面只是简单的介绍了@ComponentScan注解检测包含指定注解的自动装配,接下来让我们来看看@ComponentScan注解的更加详细的配置,在演示详细的配置之前,让我们先看看@ComponentScan的源代码如下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
   /**
    * 对应的包扫描路径 可以是单个路径,也可以是扫描的路径数组
    * @return
    */
   @AliasFor("basePackages")
   String[] value() default {};
   /**
    * 和value一样是对应的包扫描路径 可以是单个路径,也可以是扫描的路径数组
    * @return
    */
   @AliasFor("value")
   String[] basePackages() default {};
   /**
    * 指定具体的扫描的类
    * @return
    */
   Class<?>[] basePackageClasses() default {};
   /**
    * 对应的bean名称的生成器 默认的是BeanNameGenerator
    * @return
    */
   Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
   /**
    * 处理检测到的bean的scope范围
    */
   Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
   /**
    * 是否为检测到的组件生成代理
    * Indicates whether proxies should be generated for detected components, which may be
    * necessary when using scopes in a proxy-style fashion.
    * <p>The default is defer to the default behavior of the component scanner used to
    * execute the actual scan.
    * <p>Note that setting this attribute overrides any value set for {@link #scopeResolver}.
    * @see ClassPathBeanDefinitionScanner#setScopedProxyMode(ScopedProxyMode)
    */
   ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
   /**
    * 控制符合组件检测条件的类文件   默认是包扫描下的  **/*.class
    * @return
    */
   String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
   /**
    * 是否对带有@Component @Repository @Service @Controller注解的类开启检测,默认是开启的
    * @return
    */
   boolean useDefaultFilters() default true;
   /**
    * 指定某些定义Filter满足条件的组件 FilterType有5种类型如:
    *                                  ANNOTATION, 注解类型 默认
                                       ASSIGNABLE_TYPE,指定固定类
                                       ASPECTJ, ASPECTJ类型
                                       REGEX,正则表达式
                                       CUSTOM,自定义类型
    * @return
    */
   Filter[] includeFilters() default {};
   /**
    * 排除某些过来器扫描到的类
    * @return
    */
   Filter[] excludeFilters() default {};
   /**
    * 扫描到的类是都开启懒加载 ,默认是不开启的
    * @return
    */
   boolean lazyInit() default false;
}

a,演示basePackageClasses参数,如我们把配置文件改成如下:

@ComponentScan(value="com.zhang.dao",useDefaultFilters=true,basePackageClasses=UserService.class)
@Configuration
public class MainScanConfig {
}

测试结果如下:

mainScanConfig
userDao
userService

只有userDao外加basePackageClasses指定的userService加入到了spring容器中

b,演示includeFilters参数的使用如下:


在com.zhang.service包下新建一个UserService2类如下:注意没有带@Service注解

package com.zhang.service;
public class UserService2 {
}

配置类改成:

@ComponentScan(value="com.zhang",useDefaultFilters=true,
   includeFilters={
       @Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
       @Filter(type=FilterType.ASSIGNABLE_TYPE,classes={UserService2.class})
   })
@Configuration
public class MainScanConfig {
}

运行结果如下:

mainScanConfig
userController
userDao
userService
userService2

userService2同样被加入到了spring容器

新增一个自定义的实现了TypeFilter的MyTypeFilter类如下:

/**
* 自定义过滤
*
* @author zhangqh
* @date 2018年5月12日
*/
public class MyTypeFilter implements TypeFilter {
   public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
           throws IOException {
       AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
       ClassMetadata classMetadata = metadataReader.getClassMetadata();
       Resource resource = metadataReader.getResource();
       String className = classMetadata.getClassName();
       System.out.println("--->"+className);
       // 检测名字包含Service的bean
       if(className.contains("Service")){
           return true;
       }
       return false;
   }
}

修改主配置如下:

@ComponentScan(value="com.zhang",useDefaultFilters=true,
   includeFilters={
       @Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
       @Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
   })
@Configuration
public class MainScanConfig {
}

运行结果如下:

mainScanConfig
userController
userDao
userService
userService2

可以发现同样userService2被加入到了spring容器中

好了includeFilters参数就演示到这,另外一个参数excludeFilters和includeFilters用户一摸一样,只是他是过滤出不加入spring容器中,感兴趣的同学可以自己试试,我这边就不演示了

总结一下@ComponentScan的常用方式如下

  • 自定扫描路径下边带有@Controller,@Service,@Repository,@Component注解加入spring容器

  • 通过includeFilters加入扫描路径下没有以上注解的类加入spring容器

  • 通过excludeFilters过滤出不用加入spring容器的类

  • 自定义增加了@Component注解的注解方式

最后一种方式这边没有演示,算留给大家的一个小问题吧,感兴趣的同学自己实现下,有疑问也欢迎留言

以上是今天文章的所有内容,欢迎大家吐槽

原文地址:https://blog.51cto.com/4247649/2118342

深入理解spring注解之@ComponentScan注解的更多相关文章

  1. 深入理解spring中的各种注解

    Spring中的注解大概可以分为两大类: 1)spring的bean容器相关的注解,或者说bean工厂相关的注解: 2)springmvc相关的注解. spring的bean容器相关的注解,先后有:@ ...

  2. 深入理解spring中的各种注解(转)

    Spring中的注解大概可以分为两大类: 1)spring的bean容器相关的注解,或者说bean工厂相关的注解: 2)springmvc相关的注解. spring的bean容器相关的注解,先后有:@ ...

  3. Spring学习七:ComponentScan注解

    今天主要从以下几个方面来介绍一下@ComponentScan注解: @ComponentScan注解是什么 @ComponentScan注解的详细使用 1.ComponentScan注解是什么 其实很 ...

  4. 使用 Spring 2.5 基于注解驱动的 Spring MVC

    http://www.ibm.com/developerworks/cn/java/j-lo-spring25-mvc/ 概述 继 Spring 2.0 对 Spring MVC 进行重大升级后,Sp ...

  5. 使用 Spring 2.5 基于注解驱动的 Spring MVC--转

    概述 继 Spring 2.0 对 Spring MVC 进行重大升级后,Spring 2.5 又为 Spring MVC 引入了注解驱动功能.现在你无须让 Controller 继承任何接口,无需在 ...

  6. Spring系列(三):Spring IoC中各个注解的理解和使用

    原文链接:1. http://www.cnblogs.com/xdp-gacl/p/3495887.html       2. http://www.cnblogs.com/xiaoxi/p/5935 ...

  7. Spring IoC中各个注解的理解和使用

    一.把在Spring的xml文件中配置bean改为Spring的注解来配置bean 传统的Spring做法是使用.xml文件来对bean进行注入或者是配置aop.事物,这么做有两个缺点:1.如果所有的 ...

  8. 005 Spring和SpringBoot中的@Component 和@ComponentScan注解

    今天在看@ComponentScan,感觉不是太理解,下面做一个说明. 1.说明 ComponentScan做的事情就是告诉Spring从哪里找到bean 2.细节说明 如果你的其他包都在使用了@Sp ...

  9. Spring源码分析-从@ComponentScan注解配置包扫描路径到IoC容器中的BeanDefinition,经历了什么(一)?

    阅前提醒 全文较长,建议沉下心来慢慢阅读,最好是打开Idea,点开Spring源码,跟着下文一步一步阅读,更加便于理解.由于笔者水平优先,编写时间仓促,文中难免会出现一些错误或者不准确的地方,恳请各位 ...

随机推荐

  1. python-web-webbrower-beautifuSoup

    webbrowser:是 Python 自带的,打开浏览器获取指定页面. requests:从因特网上下载文件和网页. Beautiful Soup:解析 HTML,即网页编写的格式. seleniu ...

  2. Leetcode138. Copy List with Random Pointer复制带随机指针的链表

    给定一个链表,每个节点包含一个额外增加的随机指针,该指针可以指向链表中的任何节点或空节点. 要求返回这个链表的深度拷贝. 方法一: class Solution { public: RandomLis ...

  3. macOS下安装openCV+Xcode配置

    macOS下安装openCV+Xcode配置打开终端 /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Hom ...

  4. Redis源码解析:16Resis主从复制之主节点的完全重同步流程

    主从复制过程中,主节点根据从节点发来的命令执行相应的操作.结合上一章中讲解的从节点在主从复制中的流程,本章以及下一篇文章讲解一下主节点在主从复制过程中的流程. 本章主要介绍完全重同步流程. 一:从节点 ...

  5. Ubuntu下使用sshfs挂载远程目录到本地

    访问局域网中其他Ubuntu机器,在不同机器间跳来跳去,很是麻烦,如果能够把远程目录映射到本地无疑会大大方面使用,就像Windows下的网络映射盘一样.在Linux的世界无疑也会有这种机制和方式,最近 ...

  6. 获取MMSQL数据库表信息

    SELECT 表名 then d.name else '' end, 表说明 then isnull(f.value,'') else '' end, 字段序号=a.colorder, 字段名=a.n ...

  7. TZ_14_Zuul网关

    1.spring-cloud的微服务大致是 2.zuul是 Netflix开源的微服务网关, 它可以和 Eureka. Ribbon. Hystrix等组件配合使用.zul的核心是一系列的过滤器,这些 ...

  8. Thinkphp 架构笔记

    多个模块的时候,公共模块Common必须和其他模块放在同一个目录下,否则拓展配置“LOAD_EXT_CONFIG”会无效

  9. Thinkphp M方法出错,D方法却可以

    错误回顾: M('Local')->find(); //报错 //错误信息:Table 'test.local' doesn't exist [ SQL语句 ] : SHOW COLUMNS F ...

  10. Codeforces 222B 数组行列交换操作

    /*做完这题发现自己好水,太伤人了.... 不过还是学到一些,如果直接暴力模拟的话肯定是TLM.. 所以要用虚拟数组来分别保存当前数组的每行没列在初始数组中的位置...*/ #include<c ...