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、ClassPathBeanDefinitionScannerthis();register(componentClasses);refresh();}
this()是指的AnnotationConfigApplicationContext 的无参构造函数:
StartupStep 这个接口是用来记录 AnnotatedBeanDefinitionReader 这个函数运行的时间的
public AnnotationConfigApplicationContext() {StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create");// 额外会创建StandardEnvironmentthis.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 AbstractAutowireCapableBeanFactoryimplements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {}
最后一个的registerDefaultFilters:
protected void registerDefaultFilters() {// 注册@Component对应的AnnotationTypeFilterthis.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) {//扫描之后得到一个包的全部BeanDefinitionSet<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、@DescriptionAnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);}// 检查Spring容器中是否已经存在该beanNameif (checkCandidate(beanName, candidate)) {//用BeanDefinitionHolder 来包装 已经通过检查的BeanDefinitionBeanDefinitionHolder 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.componentsif (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//*.classString 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判断//构造一个BeanDefinitionScannedGenericBeanDefinition 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,将抛出IOExceptionURI getURI() throws IOException;File getFile() throws IOException;//返回某个文件,如果资源不能够被解析称为绝对路径,将会抛出FileNotFoundExceptiondefault 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,再看是否符合@Conditionalfor (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 {@Overridepublic 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());}
@Overridepublic void setBeanClassName(@Nullable String beanClassName) {this.beanClass = beanClassName;}
@Overridepublic 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的注解所指定的beanNameif (definition instanceof AnnotatedBeanDefinition) {String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);if (StringUtils.hasText(beanName)) {// 返回一个return beanName;}}// 返回一个默认的名字return buildDefaultBeanName(definition, registry);}
determineBeanNameFromAnnotation方法:返回注解中的指定的名字,如果没有返回一个null
@Nullableprotected 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、@DescriptionAnnotationConfigUtils.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容器中是否已经存在该beanNameif (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,容器中没有相同的beanNamereturn 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() + "]");}