深入理解spring注解之@ComponentScan注解

旧街凉风 提交于 2020-02-17 19:12:16

今天主要从以下几个方面来介绍一下@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;@Controllerpublic class UserController {}


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


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


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


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


新建一个配置类如下:


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


新建测试方法如下:


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


运行结果如下:


mainScanConfiguserControlleruserDaouserService


怎么样,包扫描的方式比以前介绍的通过@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)@Configurationpublic class MainScanConfig {}


测试结果如下:


mainScanConfiguserDaouserService


只有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})    })@Configurationpublic class MainScanConfig {}


运行结果如下:


mainScanConfiguserControlleruserDaouserServiceuserService2


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})    })@Configurationpublic class MainScanConfig {}


运行结果如下:


mainScanConfiguserControlleruserDaouserServiceuserService2


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


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


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


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

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

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

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

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

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

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

今天主要从以下几个方面来介绍一下@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;@Controllerpublic class UserController {}


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


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


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


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


新建一个配置类如下:


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


新建测试方法如下:


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


运行结果如下:


mainScanConfiguserControlleruserDaouserService


怎么样,包扫描的方式比以前介绍的通过@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)@Configurationpublic class MainScanConfig {}


测试结果如下:


mainScanConfiguserDaouserService


只有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})    })@Configurationpublic class MainScanConfig {}


运行结果如下:


mainScanConfiguserControlleruserDaouserServiceuserService2


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})    })@Configurationpublic class MainScanConfig {}


运行结果如下:


mainScanConfiguserControlleruserDaouserServiceuserService2


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


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


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


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

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

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

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

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

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

原文地址:https://blog.51cto.com/4247649/2118342
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!