前一篇文章: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) 复制代码
输出结果:
@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属性,定义包扫描过滤规则。