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

文章目录

  • @ComponentScan包扫描
    • 配置文件方式
      • 配置文件
      • 配置类
      • 测试类
      • 实验效果
        • 不添加包扫描的效果
        • 添加包扫描的效果
    • 注解方式
      • 配置类(主启动类)
      • 包扫描获得的其他组件
      • 测试类
      • 实验结果
  • @ComponentScan注解解析
    • value属性
    • includeFilters属性
      • 禁用默认过滤规则前
      • 禁用默认规则后
    • excludeFilters属性
      • 默认包含所有组件
      • 选择过滤类型
        • 选择过滤方式
  • 自定义过滤规则TypeFilter
    • 自定义TypeFilter的实现类
    • 使用FilterType.CUSTOM方式的包扫描
    • 实验结果
  • 拓展学习
    • MetadataReader类
    • MetadataReaderFactory类

@ComponentScan包扫描

配置文件方式

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

配置文件


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

实验效果

不添加包扫描的效果

02-组件注入-@ComponentScan包扫描_第1张图片

添加包扫描的效果

02-组件注入-@ComponentScan包扫描_第2张图片

02-组件注入-@ComponentScan包扫描_第3张图片

注解方式

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

实验结果

02-组件注入-@ComponentScan包扫描_第4张图片

02-组件注入-@ComponentScan包扫描_第5张图片

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

禁用默认过滤规则前

02-组件注入-@ComponentScan包扫描_第6张图片

禁用默认规则后

02-组件注入-@ComponentScan包扫描_第7张图片

excludeFilters属性

指定需要排除的组件

默认包含所有组件

02-组件注入-@ComponentScan包扫描_第8张图片

选择过滤类型

选择过滤方式
  • 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 {
}

02-组件注入-@ComponentScan包扫描_第9张图片

02-组件注入-@ComponentScan包扫描_第10张图片

自定义过滤规则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 {
}

02-组件注入-@ComponentScan包扫描_第11张图片

实验结果

02-组件注入-@ComponentScan包扫描_第12张图片

拓展学习

MetadataReader类

todo

MetadataReaderFactory类

todo

你可能感兴趣的:(#,组件注入,spring,java,spring)