Spring 注解驱动开发_组件注册-@ComponentScan 注解

一、@ComponentScan 自动扫描组件

1、首先创建 BookController、BookService 以及 BookDao

package org.example.controller;

import org.springframework.stereotype.Controller;

@Controller
public class BookController {
}

package org.example.service;

import org.springframework.stereotype.Service;

@Service
public class BookService {
}

package org.example.dao;

import org.springframework.stereotype.Repository;

@Repository
public class BookDao {
}

2、在配置类上添加 @ComponentScan 注解,并指明需要扫描的包

package org.example.config;

import org.example.pojo.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("org.example")
public class MainConfig {

    @Bean
    public Person person(){
        return new Person("lis", "25");
    }
}

3.测试方法

@Test
public void testComponentScan(){
    ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig.class);
    String[] names = ac.getBeanDefinitionNames();
    for (String name : names) {
        System.out.println(name);
    }
}

4、测试结果
在这里插入图片描述

二、@ComponentScan 注解的其他属性

@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;

	// 是否启用对使用 @Component @Repository、@Service 或 @Controller 注释的类的自动检测。
	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 {};

	}

}

三、@Filter 注解

3.1 excludeFilters 属性

排除带有 @Controller 注解的类,配置类如下:

package org.example.config;

import org.example.pojo.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

@Configuration
@ComponentScan(value = "org.example", excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)})
public class MainConfig {

    @Bean
    public Person person(){
        return new Person("lis", "25");
    }
}

测试方法:

@Test
public void testComponentScan(){
    ApplicationContext ac = new AnnotationConfigApplicationContext(MainConfig.class);
    String[] names = ac.getBeanDefinitionNames();
    for (String name : names) {
        System.out.println(name);
    }
}

测试结果:
在这里插入图片描述
带有 @Controller 注解的类未注入到容器中。

3.2 includeFilters

若想要 includeFilters 指定的过滤规则生效,需将 @ComponentScan 的属性 useDefaultFilters 置为 false
配置类:

package org.example.config;

import org.example.pojo.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;

@Configuration
@ComponentScan(value = "org.example", includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = Controller.class)},
        useDefaultFilters = false)
public class MainConfig {

    @Bean
    public Person person(){
        return new Person("lis", "25");
    }
}

测试方法同上,测试结果:
在这里插入图片描述
@Service注解 以及 @Repository 注解标示的类并未注入到容器中,只有 @Controller 注解标示的类添加到了容器中。

3.3 FilterType 的过滤类型

public enum FilterType {

	// 过滤类型为注解
	ANNOTATION,

	// 按照指定的类型进行过滤
	ASSIGNABLE_TYPE,

	// 按照 AspectJ 表达式进行过滤
	ASPECTJ,

	// 按照正则表达式进行过滤
	REGEX,

	// 自定义过滤规则,需实现 TypeFilter 接口
	CUSTOM

}

3.4 使用自定义过滤规则

实现 TypeFilter 接口

package org.example.config;

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;

import java.io.IOException;

public class MyTypeFilter implements TypeFilter {
    /**
     * MetadataReader:可用于读取当前正在扫描的类的信息
     * MetadataReaderFactory:MetadataReader实例的工厂接口,
     *          用于缓存每个原始资源的MetadataReader,提供了两个方法:
     *          MetadataReader getMetadataReader(String className):通过类名获取对应的MetadataReader,
     *          MetadataReader getMetadataReader(Resource resource):通过 Resource 资源获取MetadataReader
     * */
    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);
        
        // 自定义过滤规则
        if(className.contains("Con")){
            return true;
        }
        return false;
    }
}

配置类

package org.example.config;

import org.example.pojo.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

@Configuration
@ComponentScan(value = "org.example", includeFilters = {
        @ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})},
        useDefaultFilters = false)
public class MainConfig {

    @Bean
    public Person person(){
        return new Person("lis", "25");
    }
}

测试方法同 3.1,测试结果如下:
在这里插入图片描述
分析:带有虚线的类名为进入到 MyTypeFilter 类的 match 方法的 bean 的类名,但最后实际输出的只有 mainConfig、bookController,证明自定义的过滤规则生效。

总结

  • @ComponentScan 注解用于类或接口上,主要指定扫描路径,Spring会把指定路径下带有指定注解的类自动装配到bean容器里。会被自动装配的注解包括@Controller、@Service、@Component、@Repository等等。
  • @ComponentScan 注解需要与 @Configuration 注解搭配使用。其作用等同于 xml 配置文件中的<context:component-scan base-package="org.example" />配置。
  • @ComponentScan 如果未指定扫描的路径,则默认的扫描路径为该注解类所在的包
  • 通过 @ComponentScan 注解注入到容器中的 Bean,其名称默认为该类类名(首字母小写)
  • @Configuration 注解标注的类,也会被注入到容器中,该类的名称默认为类名(首字母小写)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值