文章目录
@ComponentScan包扫描
配置文件方式
- 在配置文件中配置包扫描
- 测试
- 通过包扫描自动注入@Configuration配置类组件
- 在@Configuration组件中创建bean对象
- 通过配置文件启动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);
}
}
实验效果
不添加包扫描的效果
添加包扫描的效果
注解方式
- 添加一个配置类, 在配置类中通过@ComponentScan注解配置包扫描
- 测试
- spring应用程序通过读取该配置类来启动
- 获取通过包扫描获得的其他组件
配置类(主启动类)
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);
}
}
实验结果
@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 {
}
禁用默认过滤规则前
禁用默认规则后
excludeFilters属性
指定需要排除的组件
默认包含所有组件
选择过滤类型
选择过滤方式
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 {
}
自定义过滤规则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 {
}
实验结果
拓展学习
MetadataReader类
todo
MetadataReaderFactory类
todo