package com.lnsf.rpc.extension;
import lombok.extern.slf4j.Slf4j;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* refer to dubbo spi: https://dubbo.apache.org/zh/docs/v2.7/dev/source/dubbo-spi/
* 实现思想:首先通过 ExtensionLoader 的 getExtensionLoader 方法获取一个 ExtensionLoader 实例,
* 然后再通过 ExtensionLoader 的 getExtension 方法获取拓展类对象。这其中,getExtensionLoader
* 方法用于从缓存中获取与拓展类对应的 ExtensionLoader,若缓存未命中,则创建一个新的实例。
*/
@Slf4j
public final class ExtensionLoader<T> {
/**
* 配置文件路径
*/
private static final String SERVICE_DIRECTORY = "META-INF/extensions/";
private static final Map<Class<?>, ExtensionLoader<?>> EXTENSION_LOADERS = new ConcurrentHashMap<>();
private static final Map<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<>();
private final Class<?> type;
private final Map<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<>();
private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<>();
private ExtensionLoader(Class<?> type) {
this.type = type;
}
public static <S> ExtensionLoader<S> getExtensionLoader(Class<S> type) {
if (type == null) {
throw new IllegalArgumentException("扩展类型不能为空");
}
if (!type.isInterface()) {
throw new IllegalArgumentException("扩展类型只能为接口类型");
}
if (type.getAnnotation(SPI.class) == null) {
throw new IllegalArgumentException("扩展类型必须要有@SPI注解");
}
// 从缓存中直接读取,null->创建
ExtensionLoader<S> extensionLoader = (ExtensionLoader<S>) EXTENSION_LOADERS.get(type);
if (extensionLoader == null) {
EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<S>(type));
extensionLoader = (ExtensionLoader<S>) EXTENSION_LOADERS.get(type);
}
return extensionLoader;
}
/**
* 首先检查缓存,缓存未命中则创建拓展对象
* @param name
* @return
*/
public T getExtension(String name) {
if (name == null || name.length() == 0) {
throw new IllegalArgumentException("Extension name == null");
}
// Holder,顾名思义,用于持有目标对象
Holder<Object> holder = cachedInstances.get(name);
if (holder == null) {
cachedInstances.putIfAbsent(name, new Holder<Object>());
holder = cachedInstances.get(name);
}
Object instance = holder.get();
// 双重检查
if (instance == null) {
synchronized (holder) {
instance = holder.get();
if (instance == null) {
// 创建拓展实例
instance = createExtension(name);
// 设置实例到 holder 中
holder.set(instance);
}
}
}
return (T) instance;
}
/**
* 1、通过 getExtensionClasses 获取所有的拓展类
* 2、通过反射创建拓展对象
* 第一个步骤是加载拓展类的关键
* @param name
* @return
*/
private T createExtension(String name) {
// 从配置文件中加载所有的拓展类,可得到“配置项名称”到“配置类”的映射关系表
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw new RuntimeException("没有该扩展类型" + name);
}
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
try {
// 通过反射创建实例
EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
} catch (Exception e) {
log.error(e.getMessage());
}
}
return instance;
}
/**
* 通过名称获取拓展类之前,首先需要根据配置文件解析出拓展项名称到拓展类的映射关系表(Map<名称, 拓展类>),
* 之后再根据拓展项名称从映射关系表中取出相应的拓展类即可
* @return
*/
private Map<String, Class<?>> getExtensionClasses() {
// 从缓存中获取已加载的拓展类
Map<String, Class<?>> classes = cachedClasses.get();
// 双重检查
if (classes == null) {
//同步锁,保证每次只有一个对象操作资源
synchronized (cachedClasses) {
classes = cachedClasses.get();
if (classes == null) {
classes = new HashMap<>();
// 加载拓展类
loadDirectory(classes);
cachedClasses.set(classes);
}
}
}
return classes;
}
/**
* loadDirectory 方法先通过 classLoader 获取所有资源链接,
* 然后再通过 loadResource 方法加载资源
* @param extensionClasses
*/
private void loadDirectory(Map<String, Class<?>> extensionClasses) {
// fileName = 文件夹路径 + type 全限定名
String fileName = ExtensionLoader.SERVICE_DIRECTORY + type.getName();
try {
Enumeration<URL> urls;
ClassLoader classLoader = ExtensionLoader.class.getClassLoader();
//加载本地扩展类
urls = classLoader.getResources(fileName);
//全局加载同名文件
//urls = ClassLoader.getSystemResources(fileName);
if (urls != null) {
while (urls.hasMoreElements()) {
URL resourceUrl = urls.nextElement();
//加载资源
loadResource(extensionClasses, classLoader, resourceUrl);
}
}
} catch (IOException e) {
log.error(e.getMessage());
}
}
private void loadResource(Map<String, Class<?>> extensionClasses, ClassLoader classLoader, URL resourceUrl) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resourceUrl.openStream(), "UTF-8"))) {
String line;
// 按行读取配置内容
while ((line = reader.readLine()) != null) {
// 定位 # 字符
final int ci = line.indexOf('#');
if (ci >= 0) {
// 截取 # 之前的字符串,# 之后的内容为注释,需要忽略
line = line.substring(0, ci);
}
line = line.trim();
if (line.length() > 0) {
try {
String name = null;
String clazzName = null;
final int ei = line.indexOf('=');
if (ei > 0) {
name = line.substring(0, ei).trim();
clazzName = line.substring(ei + 1).trim();
}
if (name.length() > 0 && clazzName.length() > 0) {
// 加载类,并通过 loadClass 方法对类进行缓存
Class<?> clazz = classLoader.loadClass(clazzName);
extensionClasses.put(name, clazz);
}
} catch (ClassNotFoundException e) {
log.error(e.getMessage());
}
}
}
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
毕业设计是高等教育阶段学生在完成学业前所进行的一项重要学术任务,旨在检验学生通过学习所获得的知识、技能以及对特定领域的深刻理解能力。这项任务通常要求学生运用所学专业知识,通过独立研究和创新,完成一个实际问题的解决方案或者开展一项有价值的项目。 首先,毕业设计的选择通常由学生根据个人兴趣、专业方向以及实际需求来确定。学生需要在导师的指导下明确研究目标、问题陈述,确立研究的范围和深度。毕业设计可以包括文献综述、需求分析、方案设计、实施与测试等多个阶段,以确保整个过程的科学性和系统性。 其次,毕业设计的完成通常需要学生具备一定的独立思考和解决问题的能力。在研究过程中,学生可能需要采用各种研究方法,如实验、调查、案例分析等,以获取必要的数据和信息。通过这些活动,学生能够培养扎实的专业技能,提升解决实际问题的实际能力。 第三,毕业设计的撰写是整个过程的重要组成部分。学生需要将研究过程、方法、结果以及结论等详细记录在毕业论文中,以展示其研究的全貌和成果。同时,撰写毕业设计还有助于提高学生的学术写作水平,培养清晰、逻辑的表达能力。 最后,毕业设计的评价通常由导师和相关专业人士进行。评价标准包括研究的创新性、实用性、方法的科学性以及论文的质量等方面。学生在毕业设计中获得的成绩也将直接影响其最终的学业成绩和学位授予。 总的来说,毕业设计是高等教育中的一项重要环节,通过此过程,学生不仅能够巩固所学知识,还能培养独立思考和解决问题的能力,为将来的职业发展奠定坚实的基础。
资源推荐
资源详情
资源评论
收起资源包目录
基于RPC远程调用的电影售票系统.zip (478个子文件)
.browserslistrc 30B
.browserslistrc 30B
com.lnsf.rpc.compress.compress 45B
iconfont.css 2KB
iconfont.css 2KB
global.css 537B
global.css 90B
iconfont.eot 2KB
iconfont.eot 2KB
.gitignore 268B
index.html 613B
index.html 613B
favicon.ico 4KB
favicon.ico 4KB
ExtensionLoader.java 8KB
RpcMessageDecoder.java 8KB
NettyRpcClient.java 7KB
RpcLogServiceImpl.java 7KB
FileUploadUtils.java 7KB
CuratorUtils.java 7KB
NettyRpcClientHandler.java 5KB
ThreadPoolFactoryUtils.java 5KB
RpcClientProxy.java 5KB
ConsistentHashLoadBalance.java 5KB
NettyRpcServer.java 4KB
SysBillController.java 4KB
SysMovieCommentController.java 4KB
NettyRpcServerHandler.java 4KB
RpcMessageEncoder.java 4KB
SysHallController.java 4KB
SocketRpcClient.java 3KB
SpringBeanPostProcessor.java 3KB
ServiceProviderImpl.java 3KB
KryoSerializer.java 3KB
GlobalExceptionHandler.java 3KB
SysMovieController.java 3KB
ConsumerAutoConfiguration.java 3KB
AbstractLoadBalance.java 3KB
ShiroConfig.java 3KB
CustomScannerRegistrar.java 3KB
FileUploadController.java 3KB
SysCinemaController.java 3KB
JwtUtil.java 3KB
JwtFilter.java 3KB
SocketRpcServer.java 3KB
RandomLoadBalance.java 3KB
BaseController.java 2KB
ResponseResult.java 2KB
ProtostuffSerializer.java 2KB
SysSession.java 2KB
ZkServiceDiscovery.java 2KB
SysResourceController.java 2KB
SysUserController.java 2KB
SysRoleController.java 2KB
CustomerRealm.java 2KB
RpcRequestHandler.java 2KB
SysMovieAgeController.java 2KB
RpcLogMapper.java 2KB
SysSessionController.java 2KB
SysActorController.java 2KB
SysMovieCategoryController.java 2KB
GzipCompress.java 2KB
SysHall.java 2KB
SysMovieRuntimeController.java 2KB
SysHallCategoryController.java 2KB
SysActor.java 2KB
SysCinemaBrandController.java 2KB
SysMovie.java 2KB
SocketRpcRequestHandlerRunnable.java 2KB
SysActorRoleController.java 2KB
SysCinemaAreaController.java 2KB
SysMovieAreaController.java 2KB
SysUserHobbyController.java 2KB
RpcResponse.java 2KB
SingletonFactory.java 2KB
SysCinema.java 1KB
SysMovieToCategoryController.java 1KB
ChannelProvider.java 1KB
SysActorMovieController.java 1KB
RpcRequest.java 1KB
CustomShutdownHook.java 1KB
PageBuilder.java 1KB
CustomThreadPoolConfig.java 1KB
SysLogController.java 1KB
Page.java 1KB
SysUser.java 1KB
PropertiesFileUtil.java 1KB
RpcLogService.java 1KB
ServletUtil.java 1KB
SysMovieRuntime.java 1KB
SysBill.java 1KB
ServiceProvider.java 1KB
RpcConstants.java 1KB
MimeTypeUtils.java 1KB
SysMovieComment.java 1019B
UnprocessedRequests.java 987B
ZkServiceRegistry.java 944B
StringUtil.java 878B
Serializer.java 809B
SysCinemaArea.java 804B
共 478 条
- 1
- 2
- 3
- 4
- 5
资源评论
JJJ69
- 粉丝: 6222
- 资源: 5780
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功