前言
@ComponentScan
源码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
//value和basePackages互为别名
@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 {};
}
}
重复使用
ComponentScans是ComponentScan 的容器注解。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface ComponentScans {
ComponentScan[] value();
}
两种用法
@ComponentScans(value = {@ComponentScan, @ComponentScan})
或者
@ComponentScan
@ComponentScan
Filter
在注解内部定义了一个注解名为过滤器。
@Retention(RetentionPolicy.RUNTIME)
@Target({})
@interface Filter {
FilterType type() default FilterType.ANNOTATION;
@AliasFor("classes")
Class<?>[] value() default {};
@AliasFor("value")
Class<?>[] classes() default {};
String[] pattern() default {};
}
@Target({}) 这么写代表什么意思呢 ?
在注解内部的 @Target({}) 使这个注解可以作为外层注解的属性来使用。
FilterType
public enum FilterType {
//注解
ANNOTATION,
//类型
ASSIGNABLE_TYPE,
//表达式
ASPECTJ,
//正则表达式
REGEX,
//自定义
CUSTOM
}
@Component
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
String value() default "";
}
Configuration 会给Component value赋值
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {}
Component 只有一个参数来指定组件名称。
@Indexed
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Indexed {
}
@Repository @Service @Controller
Repository
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Repository {
@AliasFor(annotation = Component.class)
String value() default "";
}
Controller
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
@AliasFor(annotation = Component.class)
String value() default "";
}
Service
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
@AliasFor(annotation = Component.class)
String value() default "";
}
这三个注解除了名字有区别实现都是一样的,通过AliasFor来给Component的value赋值。
@Service(value = "ThisIsF")
这样就将BeanDefinitionName变为了ThisIsF
ThisIsF->com.example.lurenjia.spring.c18.service.F@448ff1a8
案例1:任何参数未设置
定义一些组件
@Component
public class E {
}
@Component
class A{}
@Component
class B{}
@Component
class C{}
@Component
class D{}
执行类
@ComponentScan
public class Client {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Client .class);
for (String beanName : context.getBeanDefinitionNames()) {
System.out.println(beanName + "->" + context.getBean(beanName));
}
}
}
目录结构
输出结果
client->com.example.lurenjia.spring.c18.Client@c540f5a
a->com.example.lurenjia.spring.c18.components.A@770c2e6b
b->com.example.lurenjia.spring.c18.components.B@1a052a00
c->com.example.lurenjia.spring.c18.components.C@4d826d77
d->com.example.lurenjia.spring.c18.components.D@61009542
e->com.example.lurenjia.spring.c18.components.E@77e9807f
f->com.example.lurenjia.spring.c18.service.F@448ff1a8
案例2:basePackages
将 client 注解修改为具体包
@ComponentScan(basePackages = "com.example.lurenjia.spring.c18.service")
----
client->com.example.lurenjia.spring.c18.Client@51b7e5df
f->com.example.lurenjia.spring.c18.service.F@18a70f16
案例3:basePackageClasses
public interface ScanClass {
}
---
@Component
public class Service1 {
}
----
@Component
public class Service2 {
}
指定一个具体的类所在的包并引入包内所有组件。
@ComponentScan(basePackageClasses = ScanClass.class)
案例4:includeFilters
public interface IService {
}
public class Service1 implements IService {
}
public class Service2 implements IService {
}
@ComponentScan(
useDefaultFilters = false, //不启用默认过滤器
includeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = IService.class)
})
AssignableTypeFilter 源码
@Nullable
protected Boolean matchTargetType(String typeName) {
if (this.targetType.getName().equals(typeName)) {
return true;
}
else if (Object.class.getName().equals(typeName)) {
return false;
}
else if (typeName.startsWith("java")) {
try {
Class<?> clazz = ClassUtils.forName(typeName, getClass().getClassLoader());
return this.targetType.isAssignableFrom(clazz);
}
catch (Throwable ex) {
// Class not regularly loadable - can't determine a match that way.
}
}
return null;
}
自定义过滤器
@ComponentScan(
basePackages = {"com.example.lurenjia.spring.c18.include"},
useDefaultFilters = false,
includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = MyFilter.class)
})
public class MyFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader,
MetadataReaderFactory metadataReaderFactory) throws IOException {
Class curClass = null;
try {
//当前被扫描的类
curClass = Class.forName(metadataReader.getClassMetadata().getClassName());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//判断curClass是否是IService类型
boolean result = IService.class.isAssignableFrom(curClass);
return result;
}
}
解析原理
ConfigurationClassPostProcessor