《Spring 高手系列》(@ComponentScan )(@Component)笔记

前言

参考链接1

@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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值