仿百度网盘的一款轻量级微服务架构网盘系统,有点屌
一、前言
在gitee和github里面基本上找不到一款好用、功能完善、且开放源码的网盘系统,有一些可以免费试用但是只提供安装包,于是在利用业务时间开发了一套轻量级且易于上手的网盘系统,主要基于目前主流的前后端分离和微服务架构模式开发,里面涉及很多的解决方案,适合没有项目经验的同学学习。
网盘系统的核心目的有两个:
- 提供客户端给业务系统集成,统一管理业务系统的文件;
- 提供在线协调办公、管理个人文件的功能。系统会陆续更新和完善一些功能。
二、部署架构说明
三、技术栈说明
前端技术
- ①vue.js+ElementUI 作为基础技术框架
- ②WebUploader.js做切块上传框架
后端技术
- ①Maven+SpringBoot+SpringDataJPA作为基础架构
- ②Dubbo+Zookeeper作为服务治理架构
- ③Nacos作为配置中心
- ④Redis做分布式缓存、过期监听
- ⑤Zookeeper做分布式锁
- ⑥WebSocket+Netty做消息推送
- ⑦Solr做全文检索引擎
- ⑧FastDFS做分布式文件系统
- ⑨基于Redis+token+自定义注解实现接口幂等性
四、功能说明
1、网盘系统
- ①上传功能:主要是针对大文件的切块上传、秒传、文件夹上传
- ②下载功能:主要是大文件的切块下载;多文件(夹)合并、压缩下载
- ③文件分享:文件分享包括好友分享、私密链接分享、分享文件的转存
- ④相册管理:可以建立不同的相册来管理图片,并且可以图片在线预览功能
- ⑤回收站:删除的文件进入回收站,可以进行还原或者彻底删除
- ⑥推送功能:主要是好友分享消息推送、过期消息推送、容量更新推送
- ⑦分布式锁:主要是基于Zookeeper实现分布式锁,保证高并发情况下系统的数据安全
- ⑧过期监听:主要是基于Redis过期事件实现监听功能,包括:分享失效监听、删除过期监听等
- ⑨日志采集:通过AOP埋点的方式进行采集用户请求日志,并远程传输到日志服务端;自定义Dubbo的Filter实现链路ID的生成
- ⑩文件搜索:集成Solr框架实现全文搜索功能
- ?文件存储:集成FastDFS框架实现文件分布式存储
- ?其他琐碎功能:比如,复杂、移动、预览、删除、重命名、在线创建、在线编辑、编辑历史版本留痕等等
- ?Office在线编辑: 后期更新
- ?h5版本客户端: 预计4月25号更新
- ?c/s版本客户端: 后期更新
- ?业务系统API客户端:【 已经完成】
- ?图片新增水印: 后期更新
- ?图片在线裁剪: 后期更新
2、后台系统
- ①组件管理:主要管理文件的预览和编辑组件
- ②类型管理:主要是管理文件的格式、对应的图标、对应的预览和编辑组件
- ③日志管理:存储和展示业务系统的操作日志记录,并且可以根据追踪ID来关联所有的日志信息
循环依赖问题全景图
Spring高频面试题:如何解决循环依赖问题
什么是循环依赖问题?
类与类之间的依赖关系形成了闭环,就会导致循环依赖问题的产生。
比如下图中A类依赖了B类,B类依赖了C类,而最后C类又依赖了A类,这样就形成了循环依赖问题。
演示代码:
public class ClassA {
private ClassB classB;
public ClassB getClassB() {
return classB;
}
public void setClassB(ClassB classB) {
this.classB = classB;
}
}
public class ClassB {
private ClassA classA;
public ClassA getClassA() {
return classA;
}
public void setClassA(ClassA classA) {
this.classA = classA;
}
}
配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="classA" class="ioc.cd.ClassA">
<property name="classB" ref="classB"></property>
</bean>
<bean id="classB" class="ioc.cd.ClassB">
<property name="classA" ref="classA"></property>
</bean>
</beans>
测试代码:
@Test
public void test() throws Exception {
// 创建IoC容器,并进行初始化
String resource = "spring/spring-ioc-circular-dependency.xml";
ApplicationContext context = new ClassPathXmlApplicationContext(resource);
// 获取ClassA的实例(此时会发生循环依赖)
ClassA classA = (ClassA) context.getBean(ClassA.class);
}
通过Spring IOC流程的源码分析循环依赖问题:
以上案例有几种循环依赖问题?
循环依赖问题在Spring中主要有三种情况:
- 通过构造方法进行依赖注入时产生的循环依赖问题。
- 通过setter方法进行依赖注入且是在多例(原型)模式下产生的循环依赖问题。
- 通过setter方法进行依赖注入且是在单例模式下产生的循环依赖问题。
注意:在Spring中,只有【第三种方式】的循环依赖问题被解决了,其他两种方式在遇到循环依赖问题时都会产生异常。
其实也很好解释:
- 第一种构造方法注入的情况下,在new对象的时候就会堵塞住了,其实也就是”先有鸡还是先有蛋“的历史难题。
- 第二种setter方法&&多例的情况下,每一次getBean()时,都会产生一个新的Bean,如此反复下去就会有无穷无尽的Bean产生了,最终就会导致OOM问题的出现。
如何解决循环依赖问题?
那Spring到底是如何解决的setter方法依赖注入引起的循环依赖问题呢?请看下图(其实主要是通过两个缓存来解决的):
Spring三大缓存介绍
Spring中有三个缓存,用于存储单例的Bean实例,这三个缓存是彼此互斥的,不会针对同一个Bean的实例同时存储。
推荐:Java进阶视频资源
如果调用getBean,则需要从三个缓存中依次获取指定的Bean实例。读取顺序依次是一级缓存-->二级缓存-->三级缓存
一级缓存:Map<String, Object> singletonObjects
第一级缓存的作用?
- 用于存储单例模式下创建的Bean实例(已经创建完毕)。
- 该缓存是对外使用的,指的就是使用Spring框架的程序员。
存储什么数据?
- K:bean的名称
- V:bean的实例对象(有代理对象则指的是代理对象,已经创建完毕)
第二级缓存:Map<String, Object> earlySingletonObjects
第二级缓存的作用?
- 用于存储单例模式下创建的Bean实例(该Bean被提前暴露的引用,该Bean还在创建中)。
- 该缓存是对内使用的,指的就是Spring框架内部逻辑使用该缓存。
- 为了解决第一个classA引用最终如何替换为代理对象的问题(如果有代理对象)请爬楼参考演示案例
存储什么数据?
- K:bean的名称
- V:bean的实例对象(有代理对象则指的是代理对象,该Bean还在创建中)
第三级缓存:Map<String, ObjectFactory<?>> singletonFactories
第三级缓存的作用?
- 通过ObjectFactory对象来存储单例模式下提前暴露的Bean实例的引用(正在创建中)。
- 该缓存是对内使用的,指的就是Spring框架内部逻辑使用该缓存。
- 此缓存是解决循环依赖最大的功臣
存储什么数据?
- K:bean的名称
- V:ObjectFactory,该对象持有提前暴露的bean的引用
为什么第三级缓存要使用ObjectFactory?需要提前产生代理对象。
什么时候将Bean的引用提前暴露给第三级缓存的ObjectFactory持有?时机就是在第一步实例化之后,第二步依赖注入之前,完成此操作。
总结
以上就是Spring解决循环依赖的关键点!总结来说,就是要搞清楚以下几点:
- 搞清楚Spring三级缓存的作用?
- 搞清楚第三级缓存中ObjectFactory的作用?
- 搞清楚为什么需要第二级缓存?
- 搞清楚什么时候使用三级缓存(添加和查询操作)?
- 搞清楚什么时候使用二级缓存(添加和查询操作)?
- 当目标对象产生代理对象时,Spring容器中(第一级缓存)到底存储的是谁?
项目源码资料获取方式:关注小编+转发文章+私信【 666 】免费获取!!!
Java八股文面试资料获取方式:关注小编+转发文章+私信【 13 】免费获取!!!