开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 6 天,点击查看活动详情
一、ClassPathBeanDefinitionScanner构造器
注意:@Service、@Repository、@Controller、@Configuration都是含有@Component注解
//bean名称生成器
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
//@Scope解析器
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
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);
}
1.1 设置资源加载器
public void setResourceLoader(@Nullable ResourceLoader resourceLoader) {
//1.1.1创建资源解析器
this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
//创建元数据读取器工厂
this.metadataReaderFactory = new CachingMetadataReaderFactory(resourceLoader);
//加载META-INF/spring.components信息
this.componentsIndex = CandidateComponentsIndexLoader.loadIndex(this.resourcePatternResolver.getClassLoader());
}
1.1.1 创建资源解析器
这里因为是AnnotationConfigServletWebServerApplicationContext容器继承了GenericApplicationContext
GenericApplicationContext实现了ResourcePatternResolver所以AnnotationConfigServletWebServerApplicationContext容器也是资源解析器
public static ResourcePatternResolver getResourcePatternResolver(@Nullable ResourceLoader resourceLoader) {
if (resourceLoader instanceof ResourcePatternResolver) {
return (ResourcePatternResolver) resourceLoader;
}
else if (resourceLoader != null) {
return new PathMatchingResourcePatternResolver(resourceLoader);
}
else {
return new PathMatchingResourcePatternResolver();
}
}
1.2AnnotationBeanNameGenerator Bean名称生成器
生成Bean名称
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
//1.1.1 注解Bean
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
//1.1.2 普通Bean
return buildDefaultBeanName(definition, registry);
}
1.2.1 注解Bean
根据注解获取Bean名称
protected String determineBeanNameFromAnnotation(AnnotatedBeanDefinition annotatedDef) {
//获取注解元数据
AnnotationMetadata amd = annotatedDef.getMetadata();
//根据元数据获取Bean所有注解信息
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);
});
//判断条件 1.当前注解是否是@Component,@ManagedBean,@Named类型或者注解元数据有@Component类型 2.注解属性中含有value属性
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;
}
判断条件
- 1.当前注解是否是@Component,@ManagedBean,@Named类型或者注解元数据有@Component类型
- 2.注解属性中含有value属性
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"));
}
1.2.2 普通Bean
protected String buildDefaultBeanName(BeanDefinition definition) {
//获取全限定类名例如:com.small.autoConfig.TestAutoConfig
String beanClassName = definition.getBeanClassName();
Assert.state(beanClassName != null, "No bean class name set");
//去掉包路径获取bean名称TestAutoConfig
String shortClassName = ClassUtils.getShortName(beanClassName);
//将首字母转换成小写testAutoConfig
return Introspector.decapitalize(shortClassName);
}
1.3 AnnotationScopeMetadataResolver @Scope注解解析器
1.3.1 @Scope注解
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
//作用域范围
@AliasFor("scopeName")
String value() default "";
@AliasFor("value")
String scopeName() default "";
ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}
1.3.1.1 作用域范围:value()和scopeName()
Spring中
- singleton 饿汉加载(容器启动,Bean实例就创建好了,需要的时候从Spring容器中获取)
- prototype 懒汉加载(IOC容器启动的时候,并不会创建对象实例,每次使用都会创建一个新对象)
Springmvc中
- request 同一个请求创建一个实例
- sessioon 同一个session创建一个实例
- globalsession 同一个globalsession创建一个实例
1.3.1.2 作用域代理:proxyMode()
- DEFAULT和NO 不使用作用域代理
- INTERFACES 使用JDK动态代理模式
- TARGET_CLASS 使用Cglib代理模式
1.3.2 解析@Scope
解析@Scope注解
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
ScopeMetadata metadata = new ScopeMetadata();
//如果是注解Bean
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
//获取@Scope的属性值
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
annDef.getMetadata(), this.scopeAnnotationType);
if (attributes != null) {
//获取@Scope的value属性值,并设置作用域
metadata.setScopeName(attributes.getString("value"));
//获取@Scope的proxyMode属性值
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
//设置作用域代理
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = this.defaultProxyMode;
}
metadata.setScopedProxyMode(proxyMode);
}
}
return metadata;
}
二、doScan 扫描包
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
//2.1扫描指定包,加载成BeanDefinition
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
//2.2解析作用域
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(candidate);
//设置作用域
candidate.setScope(scopeMetadata.getScopeName());
//2.3设置Bean名称
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
//2.4 后置处理BeanDefinition
if (candidate instanceof AbstractBeanDefinition) {
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
//2.5处理公共注解
if (candidate instanceof AnnotatedBeanDefinition) {
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
//2.6检查BeanName是否冲突
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
definitionHolder =
AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
beanDefinitions.add(definitionHolder);
//2.7注册BeanDefinition
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
2.1findCandidateComponents 扫描指定包,加载成BeanDefinition
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
//如果META-INF下有spring.components则会走这逻辑(一般不用)
if (this.componentsIndex != null && indexSupportsIncludeFilters()) {
return addCandidateComponentsFromIndex(this.componentsIndex, basePackage);
}
//2.1扫描指定包路径下的类
else {
return scanCandidateComponents(basePackage);
}
}
String CLASSPATH_ALL_URL_PREFIX = "classpath*:";
static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
private String resourcePattern = DEFAULT_RESOURCE_PATTERN;
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
try {
// 2.1.1拼接包扫描路径 例如:classpath*:com/small/**/*.class
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//2.1.2 获取资源解析器并加载资源
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 {
//2.1.3将resource包装成SimpleMetadataReader并放入metadataReaderCache缓存中
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
if (isCandidateComponent(metadataReader)) {
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
//2.1.5 判断是否是顶级类或接口等
if (isCandidateComponent(sbd)) {
if (debugEnabled) {
logger.debug("Identified candidate component class: " + resource);
}
candidates.add(sbd);
}
}
}
}
}
}
----去掉日志逻辑
return candidates;
}
包名转换:把 . 转换成 /
protected String resolveBasePackage(String basePackage) {
return ClassUtils.convertClassNameToResourcePath(getEnvironment().resolveRequiredPlaceholders(basePackage));
}
// ClassUtils
private static final char PACKAGE_SEPARATOR = '.';
private static final char PATH_SEPARATOR = '/';
public static String convertClassNameToResourcePath(String className) {
Assert.notNull(className, "Class name must not be null");
return className.replace(PACKAGE_SEPARATOR, PATH_SEPARATOR);
}
前缀是 classpath*: ,中间是将包名.转换为/,后缀默认扫 **/*.class
最终拼接包路径为:classpath*:com/small/**/*.class
2.1.2 获取资源解析器并加载资源
获取包路径资源解析器,这里的资源解析器在ClassPathBeanDefinitionScanner构造器1.1中就被创建了
private ResourcePatternResolver getResourcePatternResolver() {
if (this.resourcePatternResolver == null) {
this.resourcePatternResolver = new PathMatchingResourcePatternResolver();
}
return this.resourcePatternResolver;
}
@Override
public Resource[] getResources(String locationPattern) throws IOException {
if (this.resourceLoader instanceof ResourcePatternResolver) {
return ((ResourcePatternResolver) this.resourceLoader).getResources(locationPattern);
}
return super.getResources(locationPattern);
}
PathMatchingResourcePatternResolver加载资源
public Resource[] getResources(String locationPattern) throws IOException {
Assert.notNull(locationPattern, "Location pattern must not be null");
if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
// a class path resource (multiple resources for same name possible)
if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
// a class path resource pattern
return findPathMatchingResources(locationPattern);
}
}
}
整个方法的大if结构中,先判断要扫描的包路径是否有 classpath*: ,有则截掉,之后判断路径是否能匹配扫描规则。而这个规则的匹配器,通过IDEA发现 PathMatcher 只有一个实现类: AntPathMatcher ,由此也解释了 SpringFramework 支持的是ant规则声明包。
如果规则匹配,则会进入下面的 findPathMatchingResources 方法:
protected Resource[] findPathMatchingResources(String locationPattern) throws IOException {
// 2.1.2.1 截取扫描根路径
String rootDirPath = determineRootDir(locationPattern);
String subPattern = locationPattern.substring(rootDirPath.length());
// 2.1.2.2 获取扫描包路径下的所有包
Resource[] rootDirResources = getResources(rootDirPath);
Set<Resource> result = new LinkedHashSet<>(16);
for (Resource rootDirResource : rootDirResources) {
rootDirResource = resolveRootDirResource(rootDirResource);
URL rootDirUrl = rootDirResource.getURL();
if (equinoxResolveMethod != null && rootDirUrl.getProtocol().startsWith("bundle")) {
URL resolvedUrl = (URL) ReflectionUtils.invokeMethod(equinoxResolveMethod, null, rootDirUrl);
if (resolvedUrl != null) {
rootDirUrl = resolvedUrl;
}
rootDirResource = new UrlResource(rootDirUrl);
}
if (rootDirUrl.getProtocol().startsWith(ResourceUtils.URL_PROTOCOL_VFS)) {
result.addAll(VfsResourceMatchingDelegate.findMatchingResources(rootDirUrl, subPattern, getPathMatcher()));
}
else if (ResourceUtils.isJarURL(rootDirUrl) || isJarResource(rootDirResource)) {
result.addAll(doFindPathMatchingJarResources(rootDirResource, rootDirUrl, subPattern));
}
else {
// 2.1.2.3查找路径匹配文件资源
result.addAll(doFindPathMatchingFileResources(rootDirResource, subPattern));
}
}
if (logger.isTraceEnabled()) {
logger.trace("Resolved location pattern [" + locationPattern + "] to resources " + result);
}
return result.toArray(new Resource[0]);
}
2.1.2.1 截取扫描根路径
原来路径:classpath*:com/small/**/*.class
rootDirPath截取后根路径为:classpath*:com/small/
subPattern剩余路径为:**/*.class
protected String determineRootDir(String location) {
int prefixEnd = location.indexOf(':') + 1;
int rootDirEnd = location.length();
while (rootDirEnd > prefixEnd && getPathMatcher().isPattern(location.substring(prefixEnd, rootDirEnd))) {
rootDirEnd = location.lastIndexOf('/', rootDirEnd - 2) + 1;
}
if (rootDirEnd == 0) {
rootDirEnd = prefixEnd;
}
return location.substring(0, rootDirEnd);
}
2.1.2.2 获取扫描包路径下的所有包
protected Resource[] findAllClassPathResources(String location) throws IOException {
String path = location;
if (path.startsWith("/")) {
path = path.substring(1);
}
Set<Resource> result = doFindAllClassPathResources(path);
if (logger.isTraceEnabled()) {
logger.trace("Resolved classpath location [" + location + "] to resources " + result);
}
return result.toArray(new Resource[0]);
}
这里进行真正的扫描获取包的工作:doFindAllClassPathResources
protected Set<Resource> doFindAllClassPathResources(String path) throws IOException {
Set<Resource> result = new LinkedHashSet<>(16);
ClassLoader cl = getClassLoader();
Enumeration<URL> resourceUrls = (cl != null ? cl.getResources(path) : ClassLoader.getSystemResources(path));
while (resourceUrls.hasMoreElements()) {
URL url = resourceUrls.nextElement();
result.add(convertClassLoaderURL(url));
}
if (!StringUtils.hasLength(path)) {
// The above result is likely to be incomplete, i.e. only containing file system references.
// We need to have pointers to each of the jar files on the classpath as well...
addAllClassLoaderJarRoots(cl, result);
}
return result;
}
可以发现它在做的工作是使用类加载器,把传入的根包以Resource的形式加载出来,以便后续的文件读取。
2.1.2.3查找路径匹配文件资源
获取目录资源的绝对路径:
例如:D:\java\gitee\我的项目\small-test\my-small-test\target\classes\com\small\autoConfig
rotected Set<Resource> doFindPathMatchingFileResources(Resource rootDirResource, String subPattern)
throws IOException {
File rootDir;
try {
rootDir = rootDirResource.getFile().getAbsoluteFile();
}
......
return doFindMatchingFileSystemResources(rootDir, subPattern);
}
做一些文件检查
protected Set<File> retrieveMatchingFiles(File rootDir, String pattern) throws IOException {
// 不存在的检查
if (!rootDir.exists()) {
// log
return Collections.emptySet();
}
// 非文件夹检查
if (!rootDir.isDirectory()) {
// log
return Collections.emptySet();
}
// 不可读检查
if (!rootDir.canRead()) {
// log
return Collections.emptySet();
}
String fullPattern = StringUtils.replace(rootDir.getAbsolutePath(), File.separator, "/");
if (!pattern.startsWith("/")) {
fullPattern += "/";
}
fullPattern = fullPattern + StringUtils.replace(pattern, File.separator, "/");
Set<File> result = new LinkedHashSet<>(8);
doRetrieveMatchingFiles(fullPattern, rootDir, result);
return result;
}
doRetrieveMatchingFiles:递归扫描
使用递归扫描包路径下每个资源,当资源路径匹配全路径就说明是目标资源,将其加入结果集中
D:/java/gitee/我的项目/small-test/my-small-test/target/classes/com/small/**/*.class
protected void doRetrieveMatchingFiles(String fullPattern, File dir, Set<File> result) throws IOException {
if (logger.isTraceEnabled()) {
logger.trace("Searching directory [" + dir.getAbsolutePath() +
"] for files matching pattern [" + fullPattern + "]");
}
for (File content : listDirectory(dir)) {
String currPath = StringUtils.replace(content.getAbsolutePath(), File.separator, "/");
if (content.isDirectory() && getPathMatcher().matchStart(fullPattern, currPath + "/")) {
if (!content.canRead()) {
if (logger.isDebugEnabled()) {
logger.debug("Skipping subdirectory [" + dir.getAbsolutePath() +
"] because the application is not allowed to read the directory");
}
}
else {
doRetrieveMatchingFiles(fullPattern, content, result);
}
}
//当资源路径匹配全路径就说明是目标资源,将其加入结果集中
if (getPathMatcher().match(fullPattern, currPath)) {
result.add(content);
}
}
}
2.1.3 包装resource并存入metadataReaderCache缓存中
public MetadataReader getMetadataReader(Resource resource) throws IOException {
if (this.metadataReaderCache instanceof ConcurrentMap) {
// No synchronization necessary...
MetadataReader metadataReader = this.metadataReaderCache.get(resource);
if (metadataReader == null) {
//
metadataReader = super.getMetadataReader(resource);
//放入缓存
this.metadataReaderCache.put(resource, metadataReader);
}
return metadataReader;
}
else if (this.metadataReaderCache != null) {
synchronized (this.metadataReaderCache) {
MetadataReader metadataReader = this.metadataReaderCache.get(resource);
if (metadataReader == null) {
metadataReader = super.getMetadataReader(resource);
this.metadataReaderCache.put(resource, metadataReader);
}
return metadataReader;
}
}
else {
return super.getMetadataReader(resource);
}
}
包装resource
public MetadataReader getMetadataReader(Resource resource) throws IOException {
return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
}
2.1.4 过滤、筛选Bean(可以在@ComponentScan注解中加)
protected boolean isCandidateComponent(MetadataReader metadataReader) throws IOException {
//2.1.4.1遍历excludeFilters过滤器集合,如果匹配任何一个TypeFilter,则返回false,表示没资格
for (TypeFilter tf : this.excludeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return false;
}
}
//2.1.4.2遍历includeFilters过滤器集合,如果匹配任何一个TypeFilter,则返回true,表示有资格
for (TypeFilter tf : this.includeFilters) {
if (tf.match(metadataReader, getMetadataReaderFactory())) {
return isConditionMatch(metadataReader);
}
}
return false;
}
2.1.4.1 排除过滤器
这里注入了三个排除类型过滤器
AbstractTypeHierarchyTraversingFilter,抽象方法,定义了 match 方法的模板,具体实现都交给子类实现
public abstract class AbstractTypeHierarchyTraversingFilter implements TypeFilter {
protected final Log logger = LogFactory.getLog(getClass());
// 是否考虑父类匹配
private final boolean considerInherited;
// 是否考虑接口匹配
private final boolean considerInterfaces;
protected AbstractTypeHierarchyTraversingFilter(boolean considerInherited, boolean considerInterfaces) {
this.considerInherited = considerInherited;
this.considerInterfaces = considerInterfaces;
}
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
// 提供了一个快速匹配的通道,可由子类复写
if (matchSelf(metadataReader)) {
return true;
}
// 类匹配,子类复写
ClassMetadata metadata = metadataReader.getClassMetadata();
if (matchClassName(metadata.getClassName())) {
return true;
}
// 如果考虑父类匹配
if (this.considerInherited) {
String superClassName = metadata.getSuperClassName();
if (superClassName != null) {
Boolean superClassMatch = matchSuperClass(superClassName);
if (superClassMatch != null) {
if (superClassMatch.booleanValue()) {
return true;
}
}
else {
try {
// 递归匹配父类
if (match(metadata.getSuperClassName(), metadataReaderFactory)) {
return true;
}
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not read super class [" + metadata.getSuperClassName() +
"] of type-filtered class [" + metadata.getClassName() + "]");
}
}
}
}
}
// 接口匹配
if (this.considerInterfaces) {
for (String ifc : metadata.getInterfaceNames()) {
Boolean interfaceMatch = matchInterface(ifc);
if (interfaceMatch != null) {
if (interfaceMatch.booleanValue()) {
return true;
}
}
else {
try {
if (match(ifc, metadataReaderFactory)) {
return true;
}
}
catch (IOException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Could not read interface [" + ifc + "] for type-filtered class [" +
metadata.getClassName() + "]");
}
}
}
}
}
return false;
}
// 略
}
2.1.4.2.1 ComponentScanAnnotationParser(排除启动类)
ComponentScanAnnotationParser在解析的时候添加了TypeFilter匿名实现类
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
//declaringClass为主启动类
return declaringClass.equals(className);
}
});
这个过滤器的作用是如果注入的资源是启动类就排除
2.1.4.2.2 AutoConfigurationExcludeFilter(排除配置类)
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
return isConfiguration(metadataReader) && isAutoConfiguration(metadataReader);
}
如果当前资源含有@Configuration注解并且属于自动配置类(META-INF/spring.factories下EnableAutoConfiguration)则排除
2.1.4.2.2 TypeExcludeFilter(排除配置类)
判断Bean工厂是否ListableBeanFactory类型
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
throws IOException {
//判断Bean工厂是否ListableBeanFactory类型
if (this.beanFactory instanceof ListableBeanFactory && getClass() == TypeExcludeFilter.class) {
for (TypeExcludeFilter delegate : getDelegates()) {
if (delegate.match(metadataReader, metadataReaderFactory)) {
return true;
}
}
}
return false;
}
获取容器中所有TypeExcludeFilter实例进行过滤
private Collection<TypeExcludeFilter> getDelegates() {
Collection<TypeExcludeFilter> delegates = this.delegates;
if (delegates == null) {
delegates = ((ListableBeanFactory) this.beanFactory).getBeansOfType(TypeExcludeFilter.class).values();
this.delegates = delegates;
}
return delegates;
}
因为没有TypeExcludeFilter实例所以不会走过滤逻辑
2.1.4.2 包含过滤器
这里会有@Component和@ManagedBean两种AnnotationTypeFilter注解过滤器,满足其中一个条件则会将当前类加入结果集
protected boolean matchSelf(MetadataReader metadataReader) {
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata();
return metadata.hasAnnotation(this.annotationType.getName()) ||
(this.considerMetaAnnotations && metadata.hasMetaAnnotation(this.annotationType.getName()));
}
判断条件(满足一个即可)
- 如果类上含有@Component或者@ManagedBean
- 如果类的注解元数据中含有@Component或者@ManagedBean
2.1.5 判断是否是顶级类或接口等
- metadata.isIndependent() : 判断是否可以new
- metadata.isConcrete() : 不能是接口也不能是抽象类
- metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))) : 如果是抽象类但是这个抽象类内部有随便一个方法加了@Lookup注解(CGLIB的动态代理类就会实现这个方法)
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
AnnotationMetadata metadata = beanDefinition.getMetadata();
return (metadata.isIndependent() && (metadata.isConcrete() ||
(metadata.isAbstract() && metadata.hasAnnotatedMethods(Lookup.class.getName()))));
}
2.2解析作用域(参考1.3)
2.3设置Bean名称(参考1.2)
2.4 postProcessBeanDefinition 后置处理BeanDefinition
设置 BeanDefinition 的一些默认值
protected void postProcessBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName) {
beanDefinition.applyDefaults(this.beanDefinitionDefaults);
if (this.autowireCandidatePatterns != null) {
beanDefinition.setAutowireCandidate(PatternMatchUtils.simpleMatch(this.autowireCandidatePatterns, beanName));
}
}
2.5 processCommonDefinitionAnnotations 处理公共注解
处理@Lazy、@Primary、@DependsOn、@Role、@Description属性值,设置进BeanDefinition中
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"));
}
}
2.6 checkCandidate 检查BeanName是否冲突
protected boolean checkCandidate(String beanName, BeanDefinition beanDefinition) throws IllegalStateException {
if (!this.registry.containsBeanDefinition(beanName)) {
return true;
}
BeanDefinition existingDef = this.registry.getBeanDefinition(beanName);
BeanDefinition originatingDef = existingDef.getOriginatingBeanDefinition();
if (originatingDef != null) {
existingDef = originatingDef;
}
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() + "]");
}
2.7 registerBeanDefinition 注册BeanDefinition
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
//获取Bean名称
String beanName = definitionHolder.getBeanName();
//放入beanDefinitionMap中
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
//注册Bean别名
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
总结:
第一步、扫描包路径
- 拼凑包路径为:classpath*:com/small/**/*.class
- 截取出根路径:classpath*:com/small/
- 截取资源路径下包路径:com/small/
- 使用系统类加载器(AppClassLoader)通过资源包路径获取资源全路径:/D:/java/gitee/small-test/my-small-test/target/classes/com/small/
- 拼凑路径匹配:/java/gitee/我的项目/small-test/my-small-test/target/classes/com/small/**/*.class
- 递归扫描资源全路径与路径匹配做对比,如果匹配上说明是目标资源则加入结果集返回
第二步、过滤和筛选
- 排除启动类和自动配置类(含有@Config并且属于自动配置类(META-INF/spring.factories下EnableAutoConfiguration)
- 筛选出含有@Component和@ManagedBean注解的
- 筛选可创建的对象
第三步、处理Bean信息
- 作用域、名称、注解值等