机缘
早在大学阶段就开始使用CSDN了,搜搜bug,找找项目。
但真正开始创作,开始分享自己的经验和心得还是在今年的2月份。初衷其实就是想记录一下备考计算机三级的笔记,虽然最终因为找工作等各种事宜没有考,但好在写文章、分享经验的习惯保留了下来,直到现在。
其实说实话,写作对我来说不是难事,而且我也喜欢写作,喜欢记录。大学期间就在学校的新媒体中心写公众号,自己也会偶尔发一下对生活对事情的感悟。开始在CSDN分享技术知识点、项目笔记后,我也学到了很多新知识,也逐渐对技术交流感兴趣。
收获
对我来说,最大的收获就是自己在整理创作这些文章的时候所学到的内容。不仅仅是对技术性知识的掌握,同时还有写作思路的开阔,让自己能够在掌握知识的同时,也能将所学所悟分享给外界,从而进一步查缺补漏。
目前已经有373名粉丝,虽然大家可能都是无意间看到了我写的某篇文章,但只要能起到一点点帮助作用,就足够了。
日常
就目前来说,创作已经融入进我的生活当中。在学习过程中遇到的有意思的问题,或者开发某个项目的流程,都会进行分享。
虽然这会加大工作量,因为全文都是我自己一个字一个字敲出来的,但在这个过程中也能重新梳理一遍知识,相当于重温一遍,加深记忆。
成就
截止到目前的话,我认为就是现在正在做的从0开始的RPC框架项目。
import cn.hutool.core.io.resource.ResourceUtil;
import com.khr.krpc.serializer.Serializer;
import lombok.extern.slf4j.Slf4j;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.HashMap;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* SPI加载器
* 自定义实现,支持键值对映射
*/
@Slf4j
public class SpiLoader {
/**
* 存储已加载的类:接口名 =>(key => 实现类)
*/
private static final Map<String, Map<String,Class<?>>> loaderMap = new ConcurrentHashMap<>();
/**
* 对象实例缓存(避免重复 new),类路径 => 对象实例,单例模式
*/
private static final Map<String, Object> instanceCache = new ConcurrentHashMap<>();
/**
* 系统SPI目录
*/
private static final String RPC_SYSTEM_SPI_DIR = "META-INF/rpc/system/";
/**
* 用户自定义SPI目录
*/
private static final String RPC_CUSTOM_SPI_DIR = "META-INF/rpc/custom/";
/**
* 扫描路径
*/
private static final String[] SCAN_DIRS = new String[]{RPC_SYSTEM_SPI_DIR,RPC_CUSTOM_SPI_DIR};
/**
* 动态加载的类列表
*/
private static final List<Class<?>> LOAD_CLASS_LIST = Arrays.asList(Serializer.class);
/**
* 加载所有类型
*/
public static void loadALl(){
log.info("加载所有 SPI");
for (Class<?> aClass : LOAD_CLASS_LIST){
load(aClass);
}
}
/**
* 获取某个接口的实例
*
* @param tClass
* @param key
* @param <T>
* @return
*/
public static <T> T getInstance(Class<?> tClass,String key){
String tClassName = tClass.getName();
Map<String,Class<?>> keyClassMap = loaderMap.get(tClassName);
if (keyClassMap == null){
throw new RuntimeException(String.format("SpiLoader 未加载 %s 类型",tClassName));
}
if (!keyClassMap.containsKey(key)){
throw new RuntimeException(String.format("SpiLoader 的 %s 不存在 key=%s 的类型", tClassName, key));
}
//获取到要加载的实现类型
Class<?> implClass = keyClassMap.get(key);
//从实例缓存中加载指定类型的实例
String implClassName = implClass.getName();
if (!instanceCache.containsKey(implClassName)){
try {
instanceCache.put(implClassName, implClass.newInstance());
} catch (InstantiationException | IllegalAccessException e){
String errorMsg = String.format("%s 类实例化失败",implClassName);
throw new RuntimeException(errorMsg, e);
}
}
return (T) instanceCache.get(implClassName);
}
/**
* 加载某个类型
*
* @param loadClass
* @throws IOException
*/
public static Map<String, Class<?>> load(Class<?> loadClass){
log.info("加载类型为 {} 的SPI",loadClass.getName());
//扫描路径,用户自定义的SPI优先级高于系统SPI
Map<String, Class<?>> keyClassMap = new HashMap<>();
for (String scanDir : SCAN_DIRS){
List<URL> resources = ResourceUtil.getResources(scanDir + loadClass.getName());
//读取每个资源文件
for (URL resource : resources){
try {
InputStreamReader inputStreamReader = new InputStreamReader(resource.openStream());
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line;
while ((line = bufferedReader.readLine()) != null){
String[] strArray = line.split("=");
if (strArray.length > 1){
String key = strArray[0];
String className = strArray[1];
keyClassMap.put(key, Class.forName(className));
}
}
} catch (Exception e){
log.error("spi resource load error", e);
}
}
}
loaderMap.put(loadClass.getName(),keyClassMap);
return keyClassMap;
}
public static void main(String[] args) throws IOException,ClassNotFoundException{
loadALl();
System.out.println(loaderMap);
Serializer serializer = getInstance(Serializer.class, "json");
System.out.println(serializer);
}
}
就在刚刚,我完成了项目中的SpiLoader加载器,相当于一个工具类,读取配置并加载实现类。
憧憬
实不相瞒,创作这些文章的另一个目的就是为了找工作吧。春招失利了,虽然很沮丧很emo,但也没办法,只能说自己实力不够,距离自己想去的地方想做的工作还有差距,继续加油吧,多分享多创作,希望能有个好结果。