01.本次的重点依旧是扫描函数,这次是spring中的源码:
02.第一步,构造AnnotationConfigApplicationContext
主方法:
public static void main(String[] args) {
// 创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = (UserService) applicationContext.getBean("userService");
userService.test();
}
AnnotationConfigApplicationContext 的构造函数:(这个时候是有参)
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
// 构造DefaultListableBeanFactory、AnnotatedBeanDefinitionReader、ClassPathBeanDefinitionScanner
this();
register(componentClasses);
refresh();
}
this()是指的AnnotationConfigApplicationContext 的无参构造函数:
StartupStep 这个接口是用来记录 AnnotatedBeanDefinitionReader 这个函数运行的时间的
public AnnotationConfigApplicationContext() {
StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");
// 额外会创建StandardEnvironment
this.reader = new AnnotatedBeanDefinitionReader(this);
createAnnotatedBeanDefReader.end();
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
03.来到了本次的重点类:ClassPathBeanDefinitionScanner类,这里依次执行方法
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
this(registry, true);
}
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters) {
this(registry, useDefaultFilters, getOrCreateEnvironment(registry));
}
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment) {
this(registry, useDefaultFilters, environment,
(registry instanceof ResourceLoader ? (ResourceLoader) registry : null));
}
public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry, boolean useDefaultFilters,
Environment environment, @Nullable ResourceLoader resourceLoader) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
this.registry = registry;
if (useDefaultFilters) {
registerDefaultFilters();//重点
}
setEnvironment(environment);
setResourceLoader(resourceLoader);
}
注:
这个BeanDefinitionRegistry 是注册 是一个接口
public interface BeanDefinitionRegistry extends AliasRegistry {
}
他其实有一个很重要的实现类,也是DefaultListableBeanFactory ,在扫描中起作用的其实也是DefaultListableBeanFactory ,但是这里是只需要注册,所以,还是用接口比较准确
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
}
最后一个的registerDefaultFilters:
protected void registerDefaultFilters() {
// 注册@Component对应的AnnotationTypeFilter
this.includeFilters.add(new AnnotationTypeFilter(Component.class));
ClassLoader cl = ClassPathScanningCandidateComponentProvider.class.getClassLoader();
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.annotation.ManagedBean", cl)), false));
logger.trace("JSR-250 'javax.annotation.ManagedBean' found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-250 1.1 API (as included in Java EE 6) not available - simply skip.
}
try {
this.includeFilters.add(new AnnotationTypeFilter(
((Class<? extends Annotation>) ClassUtils.forName("javax.inject.Named", cl)), false));
logger.trace("JSR-330 'javax.inject.Named' annotation found and supported for component scanning");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
04.扫描scan:我也不知道怎么就到了这个地方
public int scan(String... basePackages) {
//在容器中计算BeanDefinition的数量
int beanCountAtScanStart = this.registry.getBeanDefinitionCount();
//真正扫描的函数
doScan(basePackages);
// Register annotation config processors, if necessary.
if (this.includeAnnotationConfig) {
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
//得到本次的扫描的BeanDefinition的数量
return (this.registry.getBeanDefinitionCount() - beanCountAtScanStart);
}
05.scan中的doScan方法(重点)
//参数传入一组包名
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
//创建一个BeanDefinitionHolder的集合
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
//循环这组包名
for (String basePackage : basePackages) {
//扫描之后得到一个包的全部BeanDefinition
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
//循环这个集合
for (BeanDefinition candidate : candidates) {
//获取BeanDefinition 中的Scope注解的value值
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
//获取BeanDefinition 所代表的bean 的名字
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
// 解析@Lazy、@Primary、@DependsOn、@Role、@Description
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
// 检查Spring容器中是否已经存在该beanName
if (checkCandidate(beanName, candidate)) {
//用BeanDefinitionHolder 来包装 已经通过检查的BeanDefinition
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//添加到BeanDefinitionHolder集合中
beanDefinitions.add(definitionHolder);
// 注册
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
06.findCandidateComponents方法: 扫描之后得到一个包的全部BeanDefinition
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
//这个和简便扫描的索引文件有关,在MENF-INF的文件中的spring.components
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
else {
//一般都是这里的函数
return scanCandidateComponents(basePackage);
}
}
07.scanCandidateComponents方法(重点重点重点重点重点):
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
// 获取basePackage下所有的文件资源
//ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX 是 classpath*:
//在Spring框架中,可以使用org.springframework.core.io.support.ResourcePatternResolver接口的resolveBasePackage方法来将指定的基础包解析为用于包搜索路径的模式规范。
//例如,如果基础包是com.example.app,则可以使用resolveBasePackage方法将其解析为类路径下的资源路径,如classpath:com/example/app/。
//this.resourcePattern 是 **/*.class
//classpath*:com.xxx.xxx//*.class
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//得到所有的class 的file对象
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
boolean traceEnabled = logger.isTraceEnabled();
boolean debugEnabled = logger.isDebugEnabled();
for (Resource resource : resources) {
if (traceEnabled) {
logger.trace("Scanning " + resource);
}
if (resource.isReadable()) {
try {
//可读的话,读入元数据
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
// excludeFilters、includeFilters判断
if (isCandidateComponent(metadataReader)) { // @Component-->includeFilters判断
//构造一个BeanDefinition
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
//
sbd.setSource(resource);
//判断是不是抽象类,接口
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
else {
if (debugEnabled) {
logger.debug("Ignored because not a concrete top-level class: " + resource);
}
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not matching any filter: " + resource);
}
}
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to read candidate component class: " + resource, ex);
}
}
else {
if (traceEnabled) {
logger.trace("Ignored because not readable: " + resource);
}
}
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("I/O failure during classpath scanning", ex);
}
return candidates;
}
注释:
ResourcePatternResolver接口:默认实现类是PathMatchingResourcePatternResolver类。
public interface ResourcePatternResolver extends ResourceLoader {
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
Resource[] getResources(String locationPattern) throws IOException;
}
Resource接口:Resource一般包括这些实现类:UrlResource、ClassPathResource、FileSystemResource、ServletContextResource、InputStreamResource、ByteArrayResource
public interface Resource extends InputStreamSource {
boolean exists();
default boolean isReadable() {
return true;
}
default boolean isOpen() {//返回一个布尔值,指示此资源是否具有开放流的句柄
return false;
}
default boolean isFile() {
return false;
}
URL getURL() throws IOException;//返回一个URL句柄,如果资源不能够被解析为URL,将抛出IOException
URI getURI() throws IOException;
File getFile() throws IOException;//返回某个文件,如果资源不能够被解析称为绝对路径,将会抛出FileNotFoundException
default ReadableByteChannel readableChannel() throws IOException {
return Channels.newChannel(getInputStream());
}
long contentLength() throws IOException;
long lastModified() throws IOException;
Resource createRelative(String relativePath) throws IOException;
String getFilename();
String getDescription();
}
这里的语句的结果:resources 数组是一个个的class 的file对象 具体的类是FileSystemResource
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
08.isCandidateComponent方法:
通过传入的元数据,判断是不是这个类和容器中的已经扫描存在的excludeFilter是不是匹配,有的话,排除,不是一个bean
在@Component注解中,如果没有显示声明includeFilter,那么就会这个类的Component的includeFilter是被修饰类名
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
// 符合includeFilters的会进行条件匹配,通过了才是Bean,也就是先看有没有@Component,再看是否符合@Conditional
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
09.isConditionMatch 进一步 查看是不是有@Conditional注解
private boolean isConditionMatch(MetadataReader metadataReader) {
if (this.conditionEvaluator == null) {
this.conditionEvaluator =
new ConditionEvaluator(getRegistry(), this.environment, this.resourcePatternResolver);
}
return !this.conditionEvaluator.shouldSkip(metadataReader.getAnnotationMetadata());
}
10.shouldSkip方法:表示是不是要跳过,如果有@Conditional ,不要跳过
public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
return shouldSkip(metadata, null);
}
shouldSkip
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
//判断有无Conditional 没有就跳过
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
return false;
}
//有的话,这块是编译原理的phase
if (phase == null) {
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
}
//后面还有,但不是重点,会去执行那个实现接口的类,看一下条件是什么,成立的话,@Conditional修饰的类就会是一个bean
注释:@Conditional,参数是一个类
怎么使用@Conditional注解了?
01.先创建一个实现类,实现Condition接口:
这里写的是条件
public class User implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
try {
context.getClassLoader().loadClass("com.zhouyu.service.OrderService");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
return false;
}
}
02.使用@Conditional注解
@Component
@Conditional(User.class)
public class UserService {
}
11.回到scanCandidateComponents方法:
第7到10步,此时已经扫描完成了包,完成了判断通过,符合构造一个BeanDefinition 的条件,不匹配容器中excludeFilter,在includeFilter上有符合的,也完成了关于@Conditional判断
构造一个BeanDefinition :
ScannedGenericBeanDefinition 方法:
public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
Assert.notNull(metadataReader, "MetadataReader must not be null");
//获取元数据
this.metadata = metadataReader.getAnnotationMetadata();
// 这里只是把className设置到BeanDefinition中
setBeanClassName(this.metadata.getClassName());
setResource(metadataReader.getResource());
}
@Override
public void setBeanClassName(@Nullable String beanClassName) {
this.beanClass = beanClassName;
}
@Override
public void setResource(@Nullable Resource resource) {
this.resource = resource;
}
12.创建完成了,要判断isCandidateComponent方法,判断01.这个类是不是内部类,因为内部类也有class文件,内部类不能成为bean,02.是不是接口或者抽象类 ,这些都不能成为bean ,03.是抽象类,但是类中有一个注解@Lookup,可以成为bean
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
成功的话,把这个BeanDefinition加入数组中,结束了这个scanCandidateComponents方法
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
13.回到了doscan方法,这里获取的是Scope注解的值和beanname的值
for (BeanDefinition candidate : candidates) {
//获取Scope注解的值
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
candidate.setScope(scopeMetadata.getScopeName());
//获取beanname的值,在注解@Component中
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
14.其中的this.beanNameGenerator:
private BeanNameGenerator beanNameGenerator = AnnotationBeanNameGenerator.INSTANCE;
AnnotationBeanNameGenerator类:
public static final AnnotationBeanNameGenerator INSTANCE = new AnnotationBeanNameGenerator();
用到的方法:
AnnotationBeanNameGenerator的generateBeanName方法:
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
// 获取注解@Component的注解所指定的beanName
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// 返回一个
return beanName;
}
}
// 返回一个默认的名字
return buildDefaultBeanName(definition, registry);
}
determineBeanNameFromAnnotation方法:返回注解中的指定的名字,如果没有返回一个null
@Nullable
protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
//获得元数据
AnnotationMetadata amd = annotatedDef.getMetadata();
//获取元数据中的注解信息
Set<String> types = amd.getAnnotationTypes();
String beanName = null;
for (String type : types) {
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(amd, type);
if (attributes != null) {
Set<String> metaTypes = this.metaAnnotationTypesCache.computeIfAbsent(type, key -> {
Set<String> result = amd.getMetaAnnotationTypes(key);
return (result.isEmpty() ? Collections.emptySet() : result);
});
if (isStereotypeWithNameValue(type, metaTypes, attributes)) {
//获取value值
Object value = attributes.get("value");
if (value instanceof String) {
String strVal = (String) value;
if (StringUtils.hasLength(strVal)) {
if (beanName != null && !strVal.equals(beanName)) {
throw new IllegalStateException("Stereotype annotations suggest inconsistent " +
"component names: '" + beanName + "' versus '" + strVal + "'");
}
beanName = strVal;
}
}
}
}
}
return beanName;
}
isStereotypeWithNameValue方法:
对注解@Component判断是不是有指定的value,有的话返回value
用到的常量
private static final String COMPONENT_ANNOTATION_CLASSNAME = "org.springframework.stereotype.Component";
protected boolean isStereotypeWithNameValue(String annotationType,
Set<String> metaAnnotationTypes, @Nullable Map<String, Object> attributes) {
boolean isStereotype = annotationType.equals(COMPONENT_ANNOTATION_CLASSNAME) ||
metaAnnotationTypes.contains(COMPONENT_ANNOTATION_CLASSNAME) ||
annotationType.equals("javax.annotation.ManagedBean") ||
annotationType.equals("javax.inject.Named");
return (isStereotype && attributes != null && attributes.containsKey("value"));
}
15.回到generateBeanName方法:
buildDefaultBeanName:如果没有指定value,那么就生成一个默认的名字
protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
return buildDefaultBeanName(definition);
}
protected String buildDefaultBeanName(BeanDefinition definition) {
String beanClassName = definition.getBeanClassName();
Assert.state(beanClassName != null, "No bean class name set");
String shortClassName = ClassUtils.getShortName(beanClassName);
return Introspector.decapitalize(shortClassName);
}
这句话回生成一个默认的名字:
Introspector.decapitalize(shortClassName);
public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
Character.isUpperCase(name.charAt(0))){
return name;
}
char[] chars = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
16.再回到doscan方法:
这一步设置一些默认的值
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
// 设置BeanDefinition的默认值
beanDefinition.applyDefaults(this.beanDefinitionDefaults);
// AutowireCandidate表示某个Bean能否被用来做依赖注入
if (this.autowireCandidatePatterns != null) {
beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
}
}
具体设置那些
public void applyDefaults(BeanDefinitionDefaults defaults) {
Boolean lazyInit = defaults.getLazyInit();
if (lazyInit != null) {
setLazyInit(lazyInit);
}
setAutowireMode(defaults.getAutowireMode());
setDependencyCheck(defaults.getDependencyCheck());
setInitMethodName(defaults.getInitMethodName());
setEnforceInitMethod(false);
setDestroyMethodName(defaults.getDestroyMethodName());
setEnforceDestroyMethod(false);
}
17.一些其他的注解
if (candidate instanceof AnnotatedBeanDefinition) {
// 解析@Lazy、@Primary、@DependsOn、@Role、@Description
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
processCommonDefinitionAnnotations(abd, abd.getMetadata());
}
static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
else if (abd.getMetadata() != metadata) {
lazy = attributesFor(abd.getMetadata(), Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
}
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
abd.setRole(role.getNumber("value").intValue());
}
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
abd.setDescription(description.getString("value"));
}
}
18.再回到doscan方法:
最后一步,判断是不是已经存在bean
// 检查Spring容器中是否已经存在该beanName
if (checkCandidate(beanName, candidate)) {
//没有的话
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
// 注册
registerBeanDefinition(definitionHolder, this.registry);
}
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
if (!this.registry.containsBeanDefinition(beanName)) {
//如果没有的话,就直接返回ture,容器中没有相同的beanName
return true;
}
BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
if (originatingDef != null) {
existingDef = originatingDef;
}
// 是否兼容,如果兼容返回false表示不会重新注册到Spring容器中,如果不冲突则会抛异常。
if (isCompatible(beanDefinition, existingDef)) {
return false;
}
throw new ConflictingBeanDefinitionException("Annotation-specified bean name '" + beanName +
"' for bean class [" + beanDefinition.getBeanClassName() + "] conflicts with existing, " +
"non-compatible bean definition of same name and class [" + existingDef.getBeanClassName() + "]");
}