介绍
Erupt 是一个低代码全栈类框架,它使用Java 注解动态生成页面以及增、删、改、查、权限控制等后台功能。
零前端代码、零 CURD、自动建表,仅需一个类文件+ 简洁的注解配置,快速开发企业级 Admin 管理后台。
提供企业级中后台管理系统的全栈解决方案,大幅压缩研发周期,专注核心业务。
完美取代代码生成器,开发后台管理系统更优解!
特性 | Features
易于上手:会简单的Spring Boot基础知识即可使用简单:仅需了解@Erupt与@EruptField两个注解即可上手开发代码简洁:前端零代码,后端 template、controller、service、dao 都不需要,仅需一个类文件即可敏捷开发:仅单个.java文件即可实现后台管理功能,专注业务与核心功能的研发快速迭代:需求变更仅需修改或添加注解配置即可,迭代速度比需求讨论速度还快功能强大:动态条件处理,支持增删改查等功能代理接口,Session存储机制选择,行为日志记录等自动建表:依托于JPA可自动帮你完成数据库建表相关工作低侵入性:几乎所有功能都围绕注解而展开,不影响Spring Boot其他功能或三方库库的使用多数据源:支持:MySQL、Oracle、SQL Server、PostgreSQL、H2,甚至支持MongoDB大量组件:滑动输入、时间选择、一对多、图片上传、代码编辑器、自动完成、树、多对多、地图等23类组件丰富展示:普通文本、二维码、链接、图片、HTML、代码段、iframe、swf等代码生成:erupt代码已经足够简洁,代码生成器可进一步提升开发效率高扩展性:支持自定义数据源实现、自定义页面、动态权限管理、生命周期函数、自定义OSS等界面美观:每个交互都精心设计,产品思维打磨,只为了更好的操作体验权限管理:用户管理、角色管理、组织管理、菜单管理、登录日志、操作日志等高安全性:可靠的安全机制,登录白名单,权限验证,注解项检查,细颗粒度权限控制,为你的数据保驾护航前后端分离:后端与前端可分开部署响应式布局:支持PC端手机端等各种规格的设备中使用无需二次开发:仅需引用 jar 包即可 !支持扩展页面:可开发自定义页面,自定义弹出层,且支持:原生H5 / Freemarker / Thymeleaf等方式渲染⛰ 演示截图 | Screenshot
为什么要做 Erupt ?
无论开发怎样的系统,都需要配套的管理后台做数据支撑,是软件开发中必不可少的一环,但实际开发中存这无法规避的痛点,如:开发效率低下、接口对接繁琐、界面差强人意、代码重复、有安全漏洞,导致开发成本极高。
虽然近些年来代码生成器成了后台开发的新宠,但它真的是后台开发的最优解吗?
代码生成器的本质还是生成繁琐的前端与后台代码,一旦修改后期生成的代码很难合并,想想 Mybatis-Generator,基本上就是一次性的东西,虽然减轻了部分工作,可解决方式并非最佳。
开发后台管理系统大部分情况下只想做个普通的增删改查界面,用于数据管理,类似下面这种:
@Erupt(name = "简单的例子",power = @Power(importable = true, export = true))@Table(name = "t_simple") //数据库表名@Entitypublic class Simple extends BaseModel {@EruptField(views = @View(title = "文本"),edit = @Edit(title = "文本", notNull = true, search = @Search))private String input;@EruptField(views = @View(title = "数值", sortable = true),edit = @Edit(title = "数值", search = @Search))private Float number;@EruptField(views = @View(title = "布尔"),edit = @Edit(title = "布尔"))private Boolean bool;@EruptField(views = @View(title = "时间"),edit = @Edit(title = "时间", search = @Search(vague = true)))private Date date;}
功能体验
这个界面虽然用 Vue + Ant Design + SSM 也能做出个大概,但仔细观察会发现它有大量细节功能如:
有按钮可以查询、新增、批量删除、excel 导入导出可以对数据做筛选、隐藏某列、按某列排序表格有分页与汇总,可预览单行数据多种组件、有校验规则
全部实现这些仅前端就需要大量的代码,后端的接口与业务逻辑更不在少数。
但可以看到,用 erupt 只需要30几行代码就能完成,
完全不需要了解Angular / React / Vue / Jquery
而且不需要了解JavaScript / HTML / CSS
甚至不需要了解Spring MVC / Mybatis / SQL
即便没学过 erupt 也能猜到大部分配置的作用,只需要简单配置就能完成所有后台页面开发。
这正是建立 erupt 的初衷,对于大部分常用页面,应该使用最简单的方法来实现,甚至不需要学习各种框架和工具,专注核心业务,告别 996,省下的时间做自己喜欢做的事,从此不再因为繁琐的后台开发而焦头烂额。
下载使用 | Download
下载最新的JAR或通过Maven获取。
<!--用户权限管理--><dependency><groupId>xyz.erupt</groupId><artifactId>erupt-upms</artifactId><version>LATEST-VERSION</version></dependency><!--接口数据安全--><dependency><groupId>xyz.erupt</groupId><artifactId>erupt-security</artifactId><version>LATEST-VERSION</version></dependency><!--后台WEB界面--><dependency><groupId>xyz.erupt</groupId><artifactId>erupt-web</artifactId><version>LATEST-VERSION</version></dependency>
详细使用步骤
模块说明 | Module
erupt├── erupt-annotation -- 核心注解声明├── erupt-core -- 核心功能实现├── erupt-data -- 数据实现包├── erupt-jpa -- 关系型数据库erupt实现└── erupt-mongodb -- mongodb数据库erupt实现├── erupt-job -- 定时任务功能,支持动态定时任务,邮件发送,任务日志等功能├── erupt-security -- 接口数据安全模块├── erupt-upms -- 用户权限管理├── erupt-tpl -- 支持在 erupt 中自定义页面,自定义图表,自定义弹出层,模板引擎支持:FreeMarker / Thymeleaf / 原生H5 / Velocity 等├── erupt-generator -- 代码生成器,通过简单配置,生成 erupt 代码段└── erupt-web -- 前端页面erupt-pro├── erupt-workflow -- 基于erupt实现的工作流模块(开发中)├── erupt-dataflow -- 基于erupt实现的数据流模块(开发中)└── erupt-bi -- 通过 sql 加 js 混编实现动态报表,支持:多数据源、自定义函数、图表开发等(付费模块)erupt-site -- Erupt 官方网站 /erupts/erupt-siteerupt-web-angular -- Erupt 前端源码,暂不开放,如有自定义页面的需求,可使用 erupt-tpl 模块
技术体系 | Technology system
后端:Java 8、 ScriptEngine、 Annotation、 JDBC、 Reflect、 Spring Boot、 JPA、 Hibernate、 Quartz、 Gson、 Lombok、 POI ...
前端:JavaScript、 H5、 MVVM、 Router、 Angular CLI、 Angular、 NG-ZORRO、 NG-ALAIN、 G2Plot、 RxJS、 TypeScript、 Less ...
源码获取方式:关注小编+转发文章+私信【666】免费获取
重要的事情说三遍,转发+转发+转发,一定要记得点赞转发哦!!!
循环依赖问题全景图
什么是循环依赖问题?
类与类之间的依赖关系形成了闭环,就会导致循环依赖问题的产生。
比如下图中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="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/schema/beans/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>
测试代码:
@Testpublic 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容器中(第一级缓存)到底存储的是谁?