您正在查看: Java 分类下的文章

使用雪花算法生成16位全局唯一自增ID

背景

实际业务中,往往会用数据库自增ID来作为业务对象的唯一ID;
但数据日渐增多的互联网行业,分库分表则成了行业的通用解决方案;
此时数据库自增ID就不能满足业务需求了,行业内有各种分布式ID生成解决方案,其中雪花ID就是其中使用较多的一种。

雪花算法原理

1 基本构成

雪花算法(Snowflake)是 Twitter 开源的分布式 ID 生成算法,可以基于时间生成全局不重复的、有序的、可自增的 64 Bit 的 ID,适用于分布式系统中的 ID 生成需求。
在标准版本中由以下部分组成:
符号位(1bit)- 时间戳相对值(41bit)- 数据标志(5bit)- 机器标志(5bit)- 递增序号(12bit)
0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
一起来一共64Bit组成,其中:
1、最高位是符号位,用于区分是正数还是负数,这里始终为0,我们用不到;
2、41位的毫秒级时间戳,41位的长度可以使用69年;
3、5位datacenterId和5位workerId,加起来共10位,最多支持32 x 32 = 1024个节点
4、最后12位是毫秒内的计数,12位的计数顺序号支持每个节点每毫秒产生4096个ID序号

2 生成ID原理

- 阅读剩余部分 -

使用HotSwapAgent实现SpringBoot热加载

众所周知,IDEA 自带的热加载只支持方法内的热加载,而使用 HotSwapAgent 不仅支持方法内的热加载,并且可实现新增方法的热加载,甚至是新增类的热加载,可谓是提高开发效率的神器 真棒.png
本文主要介绍在 IDEA 下使用 HotSwapAgent 来进行 SpringBoot 下的热部署;
接下来我们开始配置 HotSwapAgent

1 安装 DCEVM

DCEVM 是个JDK的插件,提供类似 JRebel 的热加载功能,能够在运行时重新定义加载的类,实现“热加载、热插拔、热部署”,而 HotSwapAgent 插件则是实现了 Servlet 程序的热加载功能,并且 DCEVM + HotSwapAgent 开源免费,更适合广大开发者使用。
安装 DCEVM 需要和 JDK 版本相对应,你需要先确定自己的 JDK 版本是否是 DCEVM 所支持的版本
https://github.com/dcevm/dcevm/releases
写此文时,DCEVM 支持的最新 JDK 版本是Java 8u181
如果你的JDK版本不被支持,则需要去 Oracle Java Archive 这个页面下载对应版本 JDK 并安装
https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html
下载 JDK 需要自备 Oracle 的账号
下载并安装好对应版本 JDK 后,我们再次来确定 JDK 版本为对应版本
2022-02-24T13:42:56.png

- 阅读剩余部分 -

Drone下多工程项目使用Commit日志控制子工程运行

最近拖延症犯了,一个文章标题写了一个月才写了个标题... 不高兴.png

前言

自从入坑Drone CI/DI以来,我极力推荐在小微项目上使用Drone来完成自动构建,主要是轻量化,安装配置方便 吐舌.png ,
只需写一个docker compose文件即可完成Drone的安装配置,
只需写一个.drone.yml即可完成接入,极为方便;

Drone更深一层探究

经过我的不懈努力,经主管同意,最终也在公司项目上使用上了Drone来逐步替代Jenkins进行小项目微服务的自动构建部署 太开心.png

但是实际使用中发现一个问题,即SpringBoot工程,通常是一个主工程下包含多个微服务子工程,使用drone不太好控制其中某一个工程的自动构建部署,总不能每次都重新构建整个服务,然后重启所有工程吧,这样效率也太低了 不高兴.png

//多工程目录结构,本文主要演示SpringBoot多工程项目自动构建部署
demoParant
├── common   //公共工程
├── api      //API工程
├── user     //用户工程
└── back     //后台工程

能想到的最简单实现的方式就是来通过不同的分支来触发不同的构建任务,这样理论上可行,但是实际操作会产生一堆分支,显得极为不整洁,并且正常开发也是开发一个分支,测试一个分支,生产一个分支,太多了操作起来也不方便 黑线.png

所以最理想的方式也就是在同一个分支下,通过某种方式来触发不同的构建任务;

Drone的启发

在Drone CI下有一个默认功能,即在Commit log中输入[CI SKIP]即可跳过本次自动构建,于是我就想能否通过Commit log来控制本次部署具体哪个子工程,这样下来我只要在输入commit log的时候输入需要构建的工程,即可完成对应工程的自动构建部署,并且不影响同项目下的其他工程;

初步设想的原理就是在drone执行部署命令时,通过自定义脚本完成工程部署,并将commit log作为参数传入脚本,在脚本中判断commit log中是否指定某些工程的运行的参数,如果不指定则默认运行所有工程 乖.png

例如:我提交commit日志update Admin.java; add admin management interface; [CI API] [CI BACK];
这样一来,经过drone自动构建后,只重新部署了API工程和后台工程;

具体实现

具体实现可参考如下脚本:

- 阅读剩余部分 -

使用docker来构建一个SpringBoot应用

Dcoker是一个开源的应用容器引擎,介绍我就不介绍了,总之就是很牛批,用过的都相见恨晚 笑眼.png
平时我们不是应用都是先搭建相关环境,然后把应用启动一通配置好
本地环境需要搭建一次,测试环境需要搭建一次,生产环境也需要搭建一次,这样重复的工作就做了几次,效率降低 不高兴.png
使用了docker了?我们只需要构建一次镜像,然后不同的环境只需要把镜像拉下来启动就行了,是不是很简单?
如果配合CI/DI持续集成,持续部署,那就太爽歪歪了,我们只需要把代码提交到git,剩下打包/编译/测试/部署工作就全自动自己运行了,是不是大大提高了生产力? 滑稽.png
废话不多说,今天先研究docker怎么构建SpringBoot,改天再研究CI/DI~


1 安装Docker

首先docker只支持CentOS7以上的系统,如果系统版本过低请升级系统
这里我使用的是CentOS7 x64
docker安装教程详见:Docker的基本操作与使用

2 准备SpringBoot应用

- 阅读剩余部分 -

SpringBoot 配置文件存放位置及读取顺序

因为线上部署的时候和本地往往使用不同的配置文件,所以研究了下SpringBoot配置文件存放位置及读取顺序
之前是直接手动指定配置文件启动来启动SpringBoot工程的,后来发现直接按照配置文件的加载顺序优先级放到对应的文件夹下即可进行配置文件的自动覆盖和互补

以下内容转载自:https://my.oschina.net/sdlvzg/blog/1612703


SpringBoot配置文件可以使用yml格式和properties格式

分别的默认命名为:application.yml、application.properties

存放目录

SpringBoot配置文件默认可以放到以下目录中,可以自动读取到:

  • 项目根目录下
  • 项目根目录中 config 目录下
  • 项目的 resources 目录下
  • 项目 resources 目录中 config 目录下

clipboard.png

读取顺序

如果在不同的目录中存在多个配置文件,它的读取顺序是:

1、config/application.properties(项目根目录中config目录下)
2、config/application.yml
3、application.properties(项目根目录下)
4、application.yml
5、resources/config/application.properties(项目resources目录中config目录下)
6、resources/config/application.yml
7、resources/application.properties(项目的resources目录下)
8、resources/application.yml

注:
1、如果同一个目录下,有application.yml也有application.properties,默认先读取application.properties。
2、如果同一个配置属性,在多个配置文件都配置了,默认使用第1个读取到的,后面读取的不覆盖前面读取到的。
3、创建SpringBoot项目时,一般的配置文件放置在“项目的resources目录下”

解决Spring项目打成Jar包后Freemarker找不到模板的问题

昨天改完CheckDomain的bug后,打包jar准备部署到服务器上,本地测试都正常,但是扔到服务器上却发不了邮件了... 不高兴.png

经过多次测试发现,freemarker在jar包中无法使用类加载器获取resourse目录下的templates文件 泪.png

出现的问题代码如下:(本地测试正常,打包jar后无法获取模板)

/**
 * 邮件模板静态化
 *
 * @param mailTemplateModel 模板数据模型
 * @return 加上数据后的静态化模板
 */
@Override
public String getMailHtml(MailTemplateModel mailTemplateModel) {
    try {
        //创建配置类
        Configuration configuration = new Configuration(Configuration.getVersion());
        //设置模板路径
        String classpath = this.getClass().getResource("/").getPath();
        configuration.setDirectoryForTemplateLoading(new File(classpath + "/templates"));
        //设置字符集
        configuration.setDefaultEncoding("utf-8");
        //加载模板
        Template template = configuration.getTemplate("mailTemplate.ftl");
        //模板静态化并返回
        return FreeMarkerTemplateUtils.processTemplateIntoString(template, mailTemplateModel);
    } catch (Exception e) {
        e.printStackTrace();
        log.error("模板静态化异常", e);
        return null;
    }
}

修改后的代码:(打包jar后正常获取模板)

- 阅读剩余部分 -

记一次解决RestTemplate无法解析api返回的xml数据问题

最近看上了个本命域名,因为过期即将被注册局删除,于是就自己写了个api接口用来监控这个域名,等可以注册了就直接发邮件通知我 吐舌.png

其中用到了阿里云域名的一个api,准备直接使用RestTemplate去请求这个接口,并将结果自动封装为Map集合方便进行进一步处理。

等到框架搭好,代码写完,以为万事大吉的时候,程序却给我来了个惊喜: 疑问.png
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [interface java.util.Map] and content type [text/plain;charset=GBK]

很明显,上面提示接口返回的是text/plain文本类型数据,RestTemplate解析数据的时候没有找到合适的解析器,就抛了异常。
WTF? what.png 我看阿里云的接口明明返回的是xml的数据啊......仔细再定睛一看,类型还真的是文本类型...

- 阅读剩余部分 -

Git分布式版本控制工具

1 Git概述

1.1 Git历史

Git 诞生于一个极富纷争大举创新的年代。Linux 内核开源项目有着为数众多的参与者。 绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间)。 到 2002 年,整个项目组开始启用一个专有的分布式版本控制系统 BitKeeper 来管理和维护代码。

到了 2005 年,开发 BitKeeper 的商业公司同 Linux 内核开源社区的合作关系结束,他们收回了 Linux 内核社区免费使用 BitKeeper 的权力。 这就迫使 Linux 开源社区(特别是 Linux 的缔造者 Linus Torvalds)基于使用 BitKeeper 时的经验教训,开发出自己的版本系统。

他们对新的系统制订了若干目标:

  • 速度
  • 简单的设计
  • 对非线性开发模式的强力支持(允许成千上万个并行开发的分支)
  • 完全分布式
  • 有能力高效管理类似 Linux 内核一样的超大规模项目(速度和数据量)

1.2 Git与SVN对比

SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而开发人员工作的时候,用的都是自己的电脑,所以首先要从中央服务器下载最新的版本,然后开发,开发完后,需要把自己开发的代码提交到中央服务器。

集中式版本控制工具缺点:

- 阅读剩余部分 -

mybatis03 - 多表查询、简单的SSM整合

1 Mybatis多表查询

1.1 一对一查询

1.1.1 一对一查询的模型

用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户

一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户

图片1.png

1.1.2一对一查询的语句

对应的sql语句:SELECT *,o.id oid FROM orders o, USER u WHERE o.uid = u.id;

查询的结果如下:

图片2.png

- 阅读剩余部分 -

mybatis02 - 核心配置文件深入

1 Mybatis的Dao层实现

1.1 传统开发方式

1.1.1 编写UserDao接口
public interface UserDao {
    List<User> findAll() throws IOException;
}
1.1.2 编写UserDaoImpl实现
public class UserDaoImpl implements UserDao {
    public List<User> findAll() throws IOException {
        InputStream resourceAsStream = 
                    Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory sqlSessionFactory = new 
                    SqlSessionFactoryBuilder().build(resourceAsStream);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        List<User> userList = sqlSession.selectList("userMapper.findAll");
        sqlSession.close();
        return userList;
    }
}
1.1.3 测试传统方式
@Test
public void testTraditionDao() throws IOException {
    UserDao userDao = new UserDaoImpl();
    List<User> all = userDao.findAll();
    System.out.println(all);
}

- 阅读剩余部分 -

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5