欧博亚洲:【Spring注解驱动开发】组件注册-@ComponentScan-自动扫描组件&指定扫描规则

admin 4个月前 (06-07) 科技 42 0

写在前面

在现实项目中,我们更多的是使用Spring的包扫描功效对项目中的包举行扫描,通常在指定的包或子包中的类上标注了@Repository、@Service、@Controller、@Component注解的类都会被扫描到,并将这个类注入到Spring容器中。Spring包扫描功效可以使用XML文件举行设置,也可以直接使用@ComponentScan注解举行设置,使用@ComponentScan注解举行设置比使用XML文件设置要简朴的多。

项目工程源码已经提交到GitHub:https://github.com/suNShinelyz/spring-annotation

使用XML文件设置包扫描

我们可以在Spring的XML设置文件中设置包的扫描,在设置包扫描时,需要在Spring的XML文件中的beans节点中引入context标签,如下所示。

<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"
       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/context/spring-context.xsd ">

接下来,我们就可以在XML文件中界说要扫描的包了,如下所示。

<context:component-scan base-package="io.mykit.spring"/>

整个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"
       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.xsd">

    <context:component-scan base-package="io.mykit.spring"/>

    <bean id = "person" CLass="io.mykit.spring.bean.Person">
        <property name="name" value="binghe"></property>
        <property name="age" value="18"></property>
    </bean>
</beans>

此时,只要在io.mykit.spring包下,或者io.mykit.spring的子包下标注了@Repository、@Service、@Controller、@Component注解的类都会被扫描到,并自动注入到Spring容器中。

此时,我们划分建立PersonDao、PersonService、和PersonController类,并在这三个类中划分添加@Repository、@Service、@Controller注解,如下所示。

  • PersonDao
package io.mykit.spring.plugins.register.dao;

import org.springframework.stereotype.Repository;

/**
 * @author binghe
 * @version 1.0.0
 * @description 测试的dao
 */
@Repository
public class PersonDao {
}
  • PersonService
package io.mykit.spring.plugins.register.service;

import org.springframework.stereotype.Service;

/**
 * @author binghe
 * @version 1.0.0
 * @description 测试的Service
 */
@Service
public class PersonService {
}
  • PersonController
package io.mykit.spring.plugins.register.controller;

import org.springframework.stereotype.Controller;

/**
 * @author binghe
 * @version 1.0.0
 * @description 测试的controller
 */
@Controller
public class PersonController {
}

接下来,我们在SpringBeanTest类中新建一个测试方式tesT.O.PonentScaNByXml()举行测试,如下所示。

@Test
public void testComponentScanByXml(){
    APPlicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    String[] names = context.getBeanDefinitionNames();
    Arrays.stream(names).forEach(System.out::println);
}

运行测试用例,输出的效果信息如下所示。

personConfIG
personController
personDao
personService
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
person

可以看到,除了输出我们自己建立的bean名称之外,也输出了Spring内部使用的一些主要的bean名称。

接下来,我们使用注解来完成这些功效。

使用注解设置包扫描

使用@ComponentScan注解之前我们先将beans.xml文件中的下述设置注释。

<context:component-scan base-package="io.mykit.spring"></context:component-scan>

注释后如下所示。

<!--<context:component-scan base-package="io.mykit.spring"></context:component-scan>-->

使用@ComponentScan注解设置包扫描就异常Easy了!在我们的PersonConfig类上添加@ComponentScan注解,并将扫描的包指定为io.mykit.spring即可,整个的PersonConfig类如下所示。

package io.mykit.spring.plugins.register.config;

import io.mykit.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author binghe
 * @version 1.0.0
 * @description 以注解的形式来设置Person
 */
@Configuration
@ComponentScan(value = "io.mykit.spring")
public class PersonConfig {

    @Bean("person")
    public Person person01(){
        return new Person("binghe001", 18);
    }
}

没错,就是这么简朴,只需要在类上添加@ComponentScan(value = "io.mykit.spring")注解即可。

接下来,我们在SpringBeanTest类中新增testComponentScanByAnnotation()方式,如下所示。

@Test
public void testComponentScanByAnnotation(){
    ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig.class);
    String[] names = context.getBeanDefinitionNames();
    Arrays.stream(names).forEach(System.out::println);
}

运行testComponentScanByAnnotation()方式输出的效果信息如下所示。

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
personConfig
personController
personDao
personService
person

可以看到使用@ComponentScan注解同样输出了bean的名称。

既然使用XML文件和注解的方式都能够将响应的类注入到Spring容器当中,那我们是使用XML文件照样使用注解呢?我更倾向于使用注解,若是你确实喜欢使用XML文件举行设置,也可以,哈哈,小我私家喜好嘛!好了,我们继续。

关于@ComponentScan注解

我们点开ComponentScan注解类,如下所示。

package org.springframework.context.annotation;

import jAVa.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AliasFor;
import org.springframework.core.type.filter.TypeFilter;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {

	@AliasFor("basePackages")
	String[] value() default {};

	@AliasFor("value")
	String[] basePackages() default {};

	Class<?>[] basePackageClasses() default {};

	Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

	Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

	ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

	String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;

	boolean useDefaultFilters() default true;

	Filter[] includeFilters() default {};

	Filter[] excludeFilters() default {};

	boolean lazyInit() default false;

	@Retention(RetentionPolicy.RUNTIME)
	@Target({})
	@interface Filter {
		FilterType type() default FilterType.ANNOTATION;
        
		@AliasFor("classes")
		Class<?>[] value() default {};
        
		@AliasFor("value")
		Class<?>[] classes() default {};
        
		String[] pattern() default {};
	}
}

这里,我们着重来看ComponentScan类的两个方式,如下所示。

Filter[] includeFilters() default {};
Filter[] excludeFilters() default {};

includeFilters()方式示意Spring扫描的时刻,只包罗哪些注解,而excludeFilters()方式示意不包罗哪些注解。两个方式的返回值都是Filter[]数组,在ComponentScan注解类的内部存在Filter注解类,人人可以看下上面的代码。

1.扫描时清扫注解标注的类

例如,我们现在清扫@Controller、@Service和@Repository注解,我们可以在PersonConfig类上通过@ComponentScan注解的excludeFilters()实现。例如,我们在PersonConfig类上添加了如下的注解。

@ComponentScan(value = "io.mykit.spring", excludeFilters = {
        @Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class, Repository.class})
})

这样,我们就使得Spring在扫描包的时刻清扫了使用@Controller、@Service和@Repository注解标注的类。运行SpringBeanTest类中的testComponentScanByAnnotation()方式,输出的效果信息如下所示。

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
personConfig
person

可以看到,输出的效果信息中不再输出personController、personService和personDao说明Spring在举行包扫描时,忽略了@Controller、@Service和@Repository注解标注的类。

2.扫描时只包罗注解标注的类

我们也可以使用ComponentScan注解类的includeFilters()来指定Spring在举行包扫描时,只包罗哪些注解标注的类。

这里需要注重的是,当我们使用includeFilters()来指定只包罗哪些注解标注的类时,需要禁用默认的过滤规则。

例如,我们需要Spring在扫描时,只包罗@Controller注解标注的类,可以在PersonConfig类上添加@ComponentScan注解,设置只包罗@Controller注解标注的类,并禁用默认的过滤规则,如下所示。

@ComponentScan(value = "io.mykit.spring", includeFilters = {
        @Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
}, useDefaultFilters = false)

此时,我们再次运行SpringBeanTest类的testComponentScanByAnnotation()方式,输出的效果信息如下所示。

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
personConfig
personController
person

可以看到,在输出的效果中,只包罗了@Controller注解标注的组件名称,并没有输出@Service和@Repository注解标注的组件名称。

注重:在使用includeFilters()来指定只包罗哪些注解标注的类时,效果信息中会一同输出Spring内部的组件名称。

3.重复注解

不知道小伙伴们有没有注重到ComponentScan注解类上有一个如下所示的注解。

@Repeatable(ComponentScans.class)

我们先来看看@ComponentScans注解是个啥,如下所示。

package org.springframework.context.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ComponentScans {
	ComponentScan[] value();
}

可以看到,在ComponentScans注解类中只声明晰一个返回ComponentScan[]数组的value(),说到这里,人人是不是就明了了,没错,这在Java8中是一个重复注解。

对于Java8不熟悉的小伙伴,可以到【Java8新特征】专栏查看关于Java8新特征的文章。专栏地址小伙伴们可以猛戳下面的链接地址举行查看:

https://mp.weixin.qq.com/mp/appmsgalbum?action=getalbum&__biz=Mzg3MzE1NTIzNA==&scene=1&album_id=1325066823947321344#wechat_redirect

在Java8中示意@ComponentScan注解是一个重复注解,可以在一个类上重复使用这个注解,如下所示。

@Configuration
@ComponentScan(value = "io.mykit.spring", includeFilters = {
        @Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
}, useDefaultFilters = false)
@ComponentScan(value = "io.mykit.spring", includeFilters = {
        @Filter(type = FilterType.ANNOTATION, classes = {Service.class})
}, useDefaultFilters = false)
public class PersonConfig {

    @Bean("person")
    public Person person01(){
        return new Person("binghe001", 18);
    }
}

运行SpringBeanTest类的testComponentScanByAnnotation()方式,输出的效果信息如下所示。

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
personConfig
personController
personService
person

可以看到,同时输出了@Controller注解和@Service注解标注的组件名称。

若是使用的是Java8之前的版本,我们就不能直接在类上写多个@ComponentScan注解了。此时,我们可以在PersonConfig类上使用@ComponentScans注解,如下所示。

@ComponentScans(value = {
        @ComponentScan(value = "io.mykit.spring", includeFilters = {
                @Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
        }, useDefaultFilters = false),
        @ComponentScan(value = "io.mykit.spring", includeFilters = {
                @Filter(type = FilterType.ANNOTATION, classes = {Service.class})
        }, useDefaultFilters = false)
})

再次运行SpringBeanTest类的testComponentScanByAnnotation()方式,输出的效果信息如下所示。

org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
personConfig
personController
personService
person

与使用多个@ComponentScan注解输出的效果信息相同。

总结:我们可以使用@ComponentScan注解来指定Spring扫描哪些包,可以使用excludeFilters()指定扫描时清扫哪些组件,也可以使用includeFilters()指定扫描时只包罗哪些组件。当使用includeFilters()指定只包罗哪些组件时,需要禁用默认的过滤规则

好了,咱们今天就聊到这儿吧!别忘了给个在看和转发,让更多的人看到,一起学习一起提高!!

项目工程源码已经提交到GitHub:https://github.com/sunshinelyz/spring-annotation

写在最后

若是以为文章对你有点辅助,请微信搜索并关注「 冰河手艺 」微信民众号,跟冰河学习Spring注解驱动开发。民众号回复“spring注解”关键字,领取Spring注解驱动开发焦点知识图,让Spring注解驱动开发不再渺茫。

,

Allbet

www.jytjgs.com欢迎进入欧博平台(Allbet GaMing),欧博平台开放欧博(Allbet)开户、欧博(Allbet)代理开户、欧博(Allbet)电脑客户端、欧博(Allbet)APP下载等业务。

皇冠APP声明:该文看法仅代表作者自己,与本平台无关。转载请注明:欧博亚洲:【Spring注解驱动开发】组件注册-@ComponentScan-自动扫描组件&指定扫描规则

网友评论

  • (*)

最新评论

文章归档

站点信息

  • 文章总数:734
  • 页面总数:0
  • 分类总数:8
  • 标签总数:1068
  • 评论总数:403
  • 浏览总数:23259