02-组件注入-@ComponentScan包扫描

@ComponentScan包扫描

配置文件方式

  1. 在配置文件中配置包扫描
  2. 测试
    1. 通过包扫描自动注入@Configuration配置类组件
    2. 在@Configuration组件中创建bean对象
    3. 通过配置文件启动spring程序, 从容器中获取@Configuration组件中配置的bean对象

配置文件

<?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 
       https://www.springframework.org/schema/context/spring-context.xsd">

    <!--配置包扫描-->
    <context:component-scan base-package="com.xiong"/>

</beans>

配置类

package com.xiong.config;

import com.xiong.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MainConfig {
    @Bean("human")
    Person person() {
        Person person = new Person();
        person.setName("person");
        person.setAge(20);
        return person;
    }
}

测试类

package com.xiong;


import com.xiong.bean.Person;
import com.xiong.config.MainConfig;
import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainTest {
    
    @Test
    public void getBeanByXmlFileTest() {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Person person = context.getBean("person", Person.class);
        System.out.println(person);
    }
}

实验效果

不添加包扫描的效果

image-20221118030030259

添加包扫描的效果

image-20221118030146090

image-20221118030400871

注解方式

  1. 添加一个配置类, 在配置类中通过@ComponentScan注解配置包扫描
  2. 测试
    1. spring应用程序通过读取该配置类来启动
    2. 获取通过包扫描获得的其他组件

配置类(主启动类)

package com.xiong;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(value = "com.xiong")
public class SpringApplicationMain {
}

包扫描获得的其他组件

package com.xiong.config;

import com.xiong.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MainConfig {
    @Bean
    Person person() {
        Person person = new Person();
        person.setName("person");
        person.setAge(20);
        return person;
    }
}

测试类

public class MainTest {
    @Test
    public void getBeanByConfigClassTest() {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringApplicationMain.class);
        Person person = context.getBean("person", Person.class);
        System.out.println(person);
    }
}

实验结果

image-20221118031847267

image-20221118032054933

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

	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 {};
	}
}

value属性

包扫描的位置

includeFilters属性

指定只包含哪些组件

只包含哪些注解需要禁用默认的包扫描规则才能够生效

package com.xiong;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

@Configuration
@ComponentScan(value = "com.xiong",
        includeFilters = {
                @ComponentScan.Filter(
                        //指定注解方式过滤
                        type = FilterType.ANNOTATION,
                        //指定需要扫描的具体类型
                        classes = {Controller.class, Service.class}
                )
        },
        useDefaultFilters = false)
public class SpringApplicationMain {
}

禁用默认过滤规则前

image-20221118034945469

禁用默认规则后

image-20221118035243012

excludeFilters属性

指定需要排除的组件

默认包含所有组件

image-20221118034033777

选择过滤类型

选择过滤方式
  • ANNOTATION: 按照注解
  • ASPECTJ: 使用aspectj表达式
  • ASSIGNABLE_TYPE: 按照给定的class的类型
  • CUSTOM: 自定义规则
  • REGEX: 使用正则表达式
package com.xiong;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;

@Configuration
@ComponentScan(value = "com.xiong",
        excludeFilters = {
                @ComponentScan.Filter(
                        //指定注解方式过滤
                        type = FilterType.ANNOTATION,
                        //指定过滤的具体类型
                        classes = {Controller.class, Service.class}
                )
        })
public class SpringApplicationMain {
}

image-20221118034141007

image-20221118034441579

自定义过滤规则TypeFilter

使用FilterType.CUSTOM时自定义过滤器

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,

	/**
	 * 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

}

自定义TypeFilter的实现类

package com.xiong.filter;

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;
import java.util.Locale;

public class XTypeFilter implements TypeFilter {
    /**
     * @param metadataReader        读取到的当前正在扫描的类的信息
     * @param metadataReaderFactory 可以获取到其他任何类的信息
     * @return 如果成功匹配, 返回true; 否则返回false
     * @throws IOException
     */
    @Override
    public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
        //获取当前类注解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        //获取当前正在扫描的类的类信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        //获取正在扫描的类的类名
        String className = classMetadata.getClassName().toLowerCase(Locale.ROOT);
        System.out.println(className);
        //获取当前类资源(类路径classpath)
        Resource resource = metadataReader.getResource();

        // 如果扫描的类的类名中包含service(不考虑大小写的情况下), 返回true; 否则返回false
        return className.contains("service");
    }
}

使用FilterType.CUSTOM方式的包扫描

package com.xiong;

import com.xiong.filter.XTypeFilter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;

@Configuration
@ComponentScan(value = "com.xiong",
        excludeFilters = {
                @ComponentScan.Filter(
                        //指定注解方式过滤
                        type = FilterType.CUSTOM,
                        //使用自定义的包扫描规则
                        classes = {XTypeFilter.class}
                )
        })
public class SpringApplicationMain {
}

image-20221118043103395

实验结果

image-20221118043152098

拓展学习

MetadataReader类

todo

MetadataReaderFactory类

todo

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值