同步操作将从 huifer/Code-Analysis 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
在这一章笔者将和各位一起讨论一个工厂 MetadataReaderFactory
。
MetadataReaderFactory
我们先来认识 MetadataReaderFactory
接口中的一些方法定义和作用。作为一个工厂 MetadataReaderFactory
主要目的是创建一个对象,该对象是 MetadataReader
,下面我们来看 MetadataReaderFactory
中的带啊吗
MetadataReaderFactory
详细信息public interface MetadataReaderFactory {
MetadataReader getMetadataReader(String className) throws IOException;
MetadataReader getMetadataReader(Resource resource) throws IOException;
}
在 MetadataReaderFactory
接口中提供了两种方式来创建 MetadataReader
接口这两种方式都需要满足一个条件,指向 class
文件
className
创建 MetaDataReader
。Resource
创建 MetaDataReader
。下面我们来看 MetadataReaderFactory
的类图
阅读过类图后我们将跟着类图来进一步分析 MetadataReaderFactory
的多种实现。
SimpleMetadataReaderFactory
分析在进行 SimpleMetadataReaderFactory
中方法分析之前我们先要关注该对象的成员变量。在 SimpleMetadataReaderFactory
中存在一个成员变量该成员变量是 ResourceLoader
,默认为 DefaultResourceLoader
,该对象的主要作用是进行资源加载,我们这里的一个应用就是将 className
转换成 Resource
对象。
有关 ResourceLoader
和资源解析的内容各位读者可以翻阅第十八章。
getMetadataReader
法分析下面我们来看 SimpleMetadataReaderFactory#getMetadataReader(java.lang.String)
方法中的处理。
SimpleMetadataReaderFactory#getMetadataReader(java.lang.String)
方法详情@Override
public MetadataReader getMetadataReader(String className) throws IOException {
try {
String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX;
Resource resource = this.resourceLoader.getResource(resourcePath);
return getMetadataReader(resource);
}
catch (FileNotFoundException ex) {
// Maybe an inner class name using the dot name syntax? Need to use the dollar syntax here...
// ClassUtils.forName has an equivalent check for resolution into Class references later on.
int lastDotIndex = className.lastIndexOf('.');
if (lastDotIndex != -1) {
String innerClassName =
className.substring(0, lastDotIndex) + '$' + className.substring(lastDotIndex + 1);
String innerClassResourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(innerClassName) + ClassUtils.CLASS_FILE_SUFFIX;
Resource innerClassResource = this.resourceLoader.getResource(innerClassResourcePath);
if (innerClassResource.exists()) {
return getMetadataReader(innerClassResource);
}
}
throw ex;
}
}
在这个代码中主要行为操作可以简化成下面三项
className
进行转换,转化成内部类的类名(从代码上表现为文件找不到的异常处理)或者独立类的类名。ResourceLoader
)将第一项中得到的数据转换成 Resource
Resource
转换成 MetadataReader
我们重点讨论的内容是第一项,我们先来看独立类的处理
String resourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(className) + ClassUtils.CLASS_FILE_SUFFIX;
我们先将这些静态变量全部提取出来做出下面这样一个转换方法
classpath:
+ className.replace('.','/')
+.class
下面我们将 com.source.hot.ioc.book.ann.AnnBeans
进行处理,处理后会得到 classpath:com/source/hot/ioc/book/ann/AnnBeans.class
在了解了独立类的类名转换后我们来看内部类的类名转换过程
int lastDotIndex = className.lastIndexOf('.');
String innerClassName =
className.substring(0, lastDotIndex) + '$' + className.substring(lastDotIndex + 1);
String innerClassResourcePath = ResourceLoader.CLASSPATH_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(innerClassName) + ClassUtils.CLASS_FILE_SUFFIX;
比如我们现在有一个内部类 com.source.hot.ioc.book.ioc.MetadataReaderFactoryTest$A
,在这个类名上会做一次字符串拆分再重组。简而言之将最后一个.
替换为$
innerClassName
:com.source.hot.ioc.book.ioc$MetadataReaderFactoryTest$A
替换完成后又会回到我们的类名转换阶段,转换过程如下
classpath:
+ innerClassName.replace('.','/')
+.class
innerClassResourcePath
:classpath:com/source/hot/ioc/book/ioc$MetadataReaderFactoryTest$A.class
现在我们得到了所有需要的数据,下面我们就要来获取 MetadataReader
对象了。在 SimpleMetadataReaderFactory
中我们可以看代这样一段代码
@Override
public MetadataReader getMetadataReader(Resource resource) throws IOException {
return new SimpleMetadataReader(resource, this.resourceLoader.getClassLoader());
}
从这段代码中我们可以直到 MetadataReader
的获取就是创建 SimpleMetadataReader
对象。
CachingMetadataReaderFactory
分析通过前文的类图我们可以知道 CachingMetadataReaderFactory
是 SimpleMetadataReaderFactory
的子类,CachingMetadataReaderFactory
相比父类 SimpleMetadataReaderFactory
它提供了一个缓存。下面我们来看成员变量
public static final int DEFAULT_CACHE_LIMIT = 256;
@Nullable
private Map<Resource, MetadataReader> metadataReaderCache;
在 CachingMetadataReaderFactory
中存在两个成员变量,
DEFAULT_CACHE_LIMIT
:表示缓存MAP的初始化容器大小metadataReaderCache
:用于存储 Resource
和 对应的 MetadataReader
容器在这个类中我们主要关注 CachingMetadataReaderFactory#getMetadataReader
,我们在前面的分析中了解到存在缓存这一个概念同时也在父类分析中知道了获取 MetadataReader
方法,现在我们来看具体的代码
@Override
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);
}
}
从这里我们可以看到它会从 metadataReaderCache
中获取数据但是 metadataReaderCache
的类型存在多样性(在CachingMetadataReaderFactory
中有 LocalResourceCache
,该类会作为缓存的存储类的类型)。获取方式遵循下面的操作步骤
在这一章节中我们围绕 MetadataReaderFactory
接口出发了解了它的两个实现类 SimpleMetadataReaderFactory
和 CachingMetadataReaderFactory
,在分析过程中我们也比较了它们两者的差异,后者具有缓存能力前者提供基本的工厂功能。
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。