首页
友链
关于
免责声明
Search
1
王者营地战绩数据王者荣耀查询网页源码
7,918 阅读
2
群晖Active Backup for Business套件备份Linux服务器教程
4,536 阅读
3
影视分享
4,452 阅读
4
(亲测)Jrebel激活破解方式2019-08-21
4,437 阅读
5
centos7 安装及卸载 jekenis
3,696 阅读
日常
文章
后端
前端
Linux
异常
Flutter
分享
群辉
登录
Search
标签搜索
docker
springboot
Spring Boot
java
linux
Shiro
Graphics2D
图片
游戏账号交易
Mybatis
Spring Cloud
centos
脚本
Web Station
群辉
王者营地
战绩查询
平台对接
Spring Cloud Alibaba
nacos
绿林寻猫
累计撰写
249
篇文章
累计收到
26
条评论
首页
栏目
日常
文章
后端
前端
Linux
异常
Flutter
分享
群辉
页面
友链
关于
免责声明
搜索到
195
篇与
后端
的结果
2021-12-08
RabbitMQ 工作模式介绍
一、前言RabbitMQ 是一个由 erlang 开发的 AMQP (Advanced Message Queuing Protocol) 的开源实现。AMQP :高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。 AMQP 的主要特征是面向消息、队列、路由(包括点对点和发布 / 订阅)、可靠性、安全。 RabbitMQ 是一个开源的 AMQP 实现,服务器端用 Erlang 语言编写,支持多种客户端,如:Python、Ruby、.NET、Java、JMS、C、PHP、ActionScript、XMPP、STOMP 等,支持 AJAX。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。应用场景:异步处理应用解耦流量削峰上篇《Centos7 安装RabbitMQ及配置(亲测)》,今天介绍一下RabbitMQ 工作模式二、工作模式介绍2.1简单模式与工作队列模式之所以这两个模式一起介绍,是因为它们的工作原理很简单,都是由生产者、队列、消费者组成。生产者是发送消息的用户的应用程序。队列是存储消息的缓冲器。消费者是接收消息的用户的应用程序。生产者负责生产消息,将消息发送到队列中,消费者监听队列,队列有消息就进行消费。当有多个消费者时,消费者平均消费队列中的消息。2.2 发布/订阅模式图中X代表交换机,它接收来自生产者的消息,另一方面将它们推送到队列 在消息产生之前,绑定队列的消费者都能收到消息。2.3 路由模式 需要将一个队列绑定到交换机上,要求该消息与一个特定的路由键完全匹配。如果一个队列绑定到该交换机上要求路由键 (routingKey)“dog”,则只有被标记为 “dog” 的消息才被转发到该队列,不会转发 dog.puppy,也不会转发 dog.guard,只会转发dog。2.4 主题模式 发送到主题交换的消息不能具有任意的 routing_key - 它必须是由点分隔的单词列表。单词可以是任何内容,但通常它们指定与消息相关的一些功能。一些有效的路由键示例:“ stock.usd.nyse ”,“ nyse.vmw”,“ quick.orange.rabbit ”。路由密钥中可以包含任意数量的单词,最多可达255个字节。绑定密钥也必须采用相同的形式。主题交换背后的逻辑 类似于直接交换- 使用特定路由密钥发送的消息将被传递到与匹配的绑定密钥绑定的所有队列。但是绑定键有两个重要的特殊情况:(*)可以替代一个单词。(#)可以替换零个或多个单词。队列需要绑定要一个模式上。符号 “#” 匹配一个或多个词,符号“*”匹配不多不少一个词。因此“audit.#” 能够匹配到“audit.irs.corporate”,但是“audit.” 只会匹配到 “audit.irs”。相当于路由模式的模糊匹配 这里就只介绍五种模式,在 《RabbitMQ 官网》上提供了 6 中工作模式:简单模式、工作队列模式、发布/订阅模式、路由模式、主题模式 和 RPC 模式。 三、项目源码Spring Boot 整合 RabbitMQ(附源码)
2021年12月08日
254 阅读
0 评论
0 点赞
2021-12-08
Caused by: java.lang.NoClassDefFoundError: org/mybatis/logging/LoggerFactory
原有依赖: <!-- mybatis-plus --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.1.2</version> </dependency> <!--mysql--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency>异常问题:org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in class path resource [com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.ibatis.session.SqlSessionFactory]: Factory method 'sqlSessionFactory' threw exception; nested exception is java.lang.NoClassDefFoundError: org/mybatis/logging/LoggerFactory at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:627) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:607) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1288) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1127) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:538) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:498) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:320) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:318) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:846) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:863) ~[spring-context-5.1.3.RELEASE.jar:5.1.3.RELEASE] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:546) ~[spring-context-5.1.3.RELEASE.jar:5.1.3.RELEASE] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:142) ~[spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:775) [spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) [spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:316) [spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.1.RELEASE.jar:2.1.1.RELEASE] at com.comet.CometAdminApplication.main(CometAdminApplication.java:11) [classes/:na] Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.ibatis.session.SqlSessionFactory]: Factory method 'sqlSessionFactory' threw exception; nested exception is java.lang.NoClassDefFoundError: org/mybatis/logging/LoggerFactory at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:185) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:622) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE] ... 19 common frames omitted Caused by: java.lang.NoClassDefFoundError: org/mybatis/logging/LoggerFactory at com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean.<clinit>(MybatisSqlSessionFactoryBean.java:97) ~[mybatis-plus-extension-3.1.2.jar:3.1.2] at com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration.sqlSessionFactory(MybatisPlusAutoConfiguration.java:142) ~[mybatis-plus-boot-starter-3.1.2.jar:3.1.2] at com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration$$EnhancerBySpringCGLIB$$84052ef9.CGLIB$sqlSessionFactory$1(<generated>) ~[mybatis-plus-boot-starter-3.1.2.jar:3.1.2] at com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration$$EnhancerBySpringCGLIB$$84052ef9$$FastClassBySpringCGLIB$$264ba30b.invoke(<generated>) ~[mybatis-plus-boot-starter-3.1.2.jar:3.1.2] at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244) ~[spring-core-5.1.3.RELEASE.jar:5.1.3.RELEASE] at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:363) ~[spring-context-5.1.3.RELEASE.jar:5.1.3.RELEASE] at com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration$$EnhancerBySpringCGLIB$$84052ef9.sqlSessionFactory(<generated>) ~[mybatis-plus-boot-starter-3.1.2.jar:3.1.2] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131] at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131] at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154) ~[spring-beans-5.1.3.RELEASE.jar:5.1.3.RELEASE] ... 20 common frames omitted Caused by: java.lang.ClassNotFoundException: org.mybatis.logging.LoggerFactory at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_131] at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_131] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335) ~[na:1.8.0_131] at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_131] ... 32 common frames omitted添加依赖: <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-extension</artifactId> <version>3.1.2</version> </dependency>
2021年12月08日
366 阅读
0 评论
0 点赞
2021-12-08
mybatis传字符串分割
List<PayMember> moveList(Map<String,Object> map);图中parentIds为====》1,2,3 字符串
2021年12月08日
193 阅读
0 评论
0 点赞
2021-12-08
io.swagger.models.parameters.AbstractSerializableParameter: Illegal DefaultValue for parameter type
在yml中添加logging: level: io.swagger.models.parameters.AbstractSerializableParameter: error
2021年12月08日
368 阅读
0 评论
0 点赞
2021-12-08
Caused by: java.sql.SQLException: Value '0000-00-00 00:00:00' can not be represented as java.sql.Tim
异常问题:Caused by: java.sql.SQLException: Value '0000-00-00 00:00:00' can not be represented as java.sql.Timestamp原因:经过排查,发现数据表中有记录的time字段(属性为timestamp)其值为:“0000-00-00 00:00:00”或者是查询时该字段为null,在装换时间格式时出现此异常经过查询资料发现 “0000-00-00 00:00:00”在mysql中是作为一个特殊值存在的但 java.sql.Date 将其视为 不合法的值 格式不正确,所以才会报上面的错误;解决办法:在jdbc的url加上 zeroDateTimeBehavior参数:datasource.url=jdbc:mysql://localhost:3306/hunter?useUnicode=true&characterEncoding=utf8 &zeroDateTimeBehavior=convertToNullzeroDateTimeBehaviorzeroDateTimeBehavior=round是为了指定MySql中的DateTime字段默认值查询时的处理方式;默认是抛出异常,对于值为0000-00-00 00:00:00(默认值)的纪录,采用两种配置,会返回不同的结果:设置zeroDateTimeBehavior=round,返回值为 0001-01-01 00:00:00.0设置zeroDateTimeBehavior=convertToNull ,返回值为 null
2021年12月08日
258 阅读
0 评论
0 点赞
2021-12-08
支付宝接口
支付宝接口支付宝
2021年12月08日
147 阅读
0 评论
0 点赞
2021-12-08
> 1055 - Expression #2 of SELECT list is not in GROUP BY clause and contains
使用查询:select @@global.sql_mode结果:ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE, NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO, NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION centos下修改:/etc/my.cnf文件去掉ONLY_FULL_GROUP_BY,重新设置值在末尾添加[mysqld] sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION 重启MySQL服务service mysqld restart
2021年12月08日
199 阅读
0 评论
0 点赞
2021-12-08
xml转换json工具类
导入依赖 <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency>工具类 import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import org.dom4j.*; import java.io.File; import java.io.FileInputStream; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.List; import java.util.logging.Logger; /** * xml转换json工具类 * @Author: LiuYong * @Date:2019/12/11 10:00 * @Description: TODO xml转换json工具类 */ public class XmlToJsonUtils { private static Logger logger = Logger.getLogger(XmlToJsonUtils.class.getName()); public static void main(String[] args) throws Exception { String xml ="<xml>\n" + "<appid>wx2421b1c4370ec43b</appid>\n" + "<attach><![CDATA[att1]]></attach>\n" + "<body><![CDATA[JSAPI支付测试]]></body>\n" + "<device_info>1000</device_info>\n" + "<mch_id>10000100</mch_id>\n" + "<nonce_str>b927722419c52622651a871d1d9ed8b2</nonce_str>\n" + "<notify_url>http://wxpay.weixin.qq.com/pub_v2/pay/notify.php</notify_url>\n" + "<out_trade_no>1405713376</out_trade_no>\n" + "<spbill_create_ip>127.0.0.1</spbill_create_ip>\n" + "<total_fee>1</total_fee>\n" + "<trade_type>JSAPI</trade_type>\n" + "<sign><![CDATA[3CA89B5870F944736C657979192E1CF4]]></sign>\n" + "</xml>"; String s = xmlToJson(xml); System.out.println(s); JSONObject jsonObject = xml2Json(xml); System.out.println(jsonObject); } /** * xml字符串转json字符串 * @Author LiuYong * @Date 2019/12/11 10:06 * @Description TODO * @param xml * @return String **/ public static String xmlToJson(String xml) { Document doc; try { doc = DocumentHelper.parseText(xml); JSONObject json = new JSONObject(); dom4j2Json(doc.getRootElement(), json); return json.toJSONString(); } catch (DocumentException e) { logger.info("数据解析失败"); } return null; } /** * 根据xml文件路径转换json字符串 * @Author LiuYong * @Date 2019/12/11 10:06 * @Description TODO * @param path * @return String **/ public static String readFile(String path) throws Exception { File file = new File(path); FileInputStream fis = new FileInputStream(file); FileChannel fc = fis.getChannel(); ByteBuffer bb = ByteBuffer.allocate(new Long(file.length()).intValue()); /**fc向buffer中读入数据*/ fc.read(bb); bb.flip(); String str = new String(bb.array(), "UTF8"); fc.close(); fis.close(); return str; } /** * xml转json * * @param xmlStr * @return * @throws DocumentException */ public static JSONObject xml2Json(String xmlStr) throws DocumentException { Document doc = DocumentHelper.parseText(xmlStr); JSONObject json = new JSONObject(); dom4j2Json(doc.getRootElement(), json); return json; } /** * xml转json * @Author LiuYong * @Date 2019/12/11 10:07 * @Description TODO * @param element * @param json 外部接收json对象 **/ public static void dom4j2Json(Element element, JSONObject json) { /**如果是属性*/ for (Object o : element.attributes()) { Attribute attr = (Attribute) o; if (!isEmpty(attr.getValue())) { json.put("@" + attr.getName(), attr.getValue()); } } List<Element> chdEl = element.elements(); /**如果没有子元素,只有一个值*/ if (chdEl.isEmpty() && !isEmpty(element.getText())) { json.put(element.getName(), element.getText()); } /**有子元素*/ for (Element e : chdEl) { /**子元素存在子元素*/ if (!e.elements().isEmpty()) { JSONObject chdjson = new JSONObject(); dom4j2Json(e, chdjson); Object o = json.get(e.getName()); if (o != null) { JSONArray jsona = null; /**如果此元素已存在,则转为jsonArray*/ if (o instanceof JSONObject) { JSONObject jsono = (JSONObject) o; json.remove(e.getName()); jsona = new JSONArray(); jsona.add(jsono); jsona.add(chdjson); } if (o instanceof JSONArray) { jsona = (JSONArray) o; jsona.add(chdjson); } json.put(e.getName(), jsona); } else { if (!chdjson.isEmpty()) { json.put(e.getName(), chdjson); } } } else { /**子元素没有子元素*/ for (Object o : element.attributes()) { Attribute attr = (Attribute) o; if (!isEmpty(attr.getValue())) { json.put("@" + attr.getName(), attr.getValue()); } } if (!e.getText().isEmpty()) { json.put(e.getName(), e.getText()); } } } } /** * 是否为null * @Author LiuYong * @Date 2019/12/11 10:28 * @Description TODO * @param * @return **/ public static boolean isEmpty(String str) { if (str == null || str.trim().isEmpty() || str.equals("null")) { return true; } return false; } }
2021年12月08日
233 阅读
0 评论
0 点赞
2021-12-08
根据网络地址下载图片及文件
/** * @Author LiuYong * @Date 2019/12/13 17:44 * @Description TODO * @param urlList url下载地址 * @param path 保存地址 * @return **/ private static void downloadPicture(String urlList,String path) { URL url = null; try { url = new URL(urlList); DataInputStream dataInputStream = new DataInputStream(url.openStream()); FileOutputStream fileOutputStream = new FileOutputStream(new File(path)); ByteArrayOutputStream output = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int length; while ((length = dataInputStream.read(buffer)) > 0) { output.write(buffer, 0, length); } fileOutputStream.write(output.toByteArray()); dataInputStream.close(); fileOutputStream.close(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
2021年12月08日
107 阅读
0 评论
0 点赞
2021-12-08
雪花算法 Snowflake 分布式自增id
类snowflake方案这种方案大致来说是一种以划分命名空间(UUID也算,由于比较常见,所以单独分析)来生成ID的一种算法,这种方案把64-bit分别划分成多段,分开来标示机器、时间等,比如在snowflake中的64-bit分别表示如下图(图片来自网络)所示:image41-bit的时间可以表示(1L<<41)/(1000L*3600*24*365)=69年的时间,10-bit机器可以分别表示1024台机器。如果我们对IDC划分有需求,还可以将10-bit分5-bit给IDC,分5-bit给工作机器。这样就可以表示32个IDC,每个IDC下可以有32台机器,可以根据自身需求定义。12个自增序列号可以表示2^12个ID,理论上snowflake方案的QPS约为409.6w/s,这种分配方式可以保证在任何一个IDC的任何一台机器在任意毫秒内生成的ID都是不同的。这种方式的优缺点是:优点: 毫秒数在高位,自增序列在低位,整个ID都是趋势递增的。 不依赖数据库等第三方系统,以服务的方式部署,稳定性更高,生成ID的性能也是非常高的。 可以根据自身业务特性分配bit位,非常灵活。 缺点: 强依赖机器时钟,如果机器上时钟回拨,会导致发号重复或者服务会处于不可用状态。 /** * Twitter_Snowflake<br> * SnowFlake的结构如下(每部分用-分开):<br> * 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br> * 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br> * 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截) * 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下下面程序IdWorker类的startTime属性)。 * 41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br> * 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId<br> * 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号<br> * 加起来刚好64位,为一个Long型。<br> * SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分), * 并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。 */ public class SnowflakeIdWorker { // ==============================Fields=========================================== /** 开始时间截 (2015-01-01) */ private final long twepoch = 1420041600000L; /** 机器id所占的位数 */ private final long workerIdBits = 5L; /** 数据标识id所占的位数 */ private final long datacenterIdBits = 5L; /** 支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数) */ private final long maxWorkerId = -1L ^ (-1L << workerIdBits); /** 支持的最大数据标识id,结果是31 */ private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); /** 序列在id中占的位数 */ private final long sequenceBits = 12L; /** 机器ID向左移12位 */ private final long workerIdShift = sequenceBits; /** 数据标识id向左移17位(12+5) */ private final long datacenterIdShift = sequenceBits + workerIdBits; /** 时间截向左移22位(5+5+12) */ private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; /** 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095) */ private final long sequenceMask = -1L ^ (-1L << sequenceBits); /** 工作机器ID(0~31) */ private long workerId; /** 数据中心ID(0~31) */ private long datacenterId; /** 毫秒内序列(0~4095) */ private long sequence = 0L; /** 上次生成ID的时间截 */ private long lastTimestamp = -1L; //==============================Constructors===================================== /** * 构造函数 * @param workerId 工作ID (0~31) * @param datacenterId 数据中心ID (0~31) */ public SnowflakeIdWorker(long workerId, long datacenterId) { if (workerId > maxWorkerId || workerId < 0) { throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId)); } if (datacenterId > maxDatacenterId || datacenterId < 0) { throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId)); } this.workerId = workerId; this.datacenterId = datacenterId; } // ==============================Methods========================================== /** * 获得下一个ID (该方法是线程安全的) * @return SnowflakeId */ public synchronized long nextId() { long timestamp = timeGen(); //如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常 if (timestamp < lastTimestamp) { throw new RuntimeException( String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp)); } //如果是同一时间生成的,则进行毫秒内序列 if (lastTimestamp == timestamp) { sequence = (sequence + 1) & sequenceMask; //毫秒内序列溢出 if (sequence == 0) { //阻塞到下一个毫秒,获得新的时间戳 timestamp = tilNextMillis(lastTimestamp); } } //时间戳改变,毫秒内序列重置 else { sequence = 0L; } //上次生成ID的时间截 lastTimestamp = timestamp; //移位并通过或运算拼到一起组成64位的ID return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence; } /** * 阻塞到下一个毫秒,直到获得新的时间戳 * @param lastTimestamp 上次生成ID的时间截 * @return 当前时间戳 */ protected long tilNextMillis(long lastTimestamp) { long timestamp = timeGen(); while (timestamp <= lastTimestamp) { timestamp = timeGen(); } return timestamp; } /** * 返回以毫秒为单位的当前时间 * @return 当前时间(毫秒) */ protected long timeGen() { return System.currentTimeMillis(); } //==============================Test============================================= /** 测试 */ public static void main(String[] args) { SnowflakeIdWorker idWorker = new SnowflakeIdWorker(1, 0); for (int i = 0; i < 1000; i++) { long id = idWorker.nextId(); System.out.println(Long.toBinaryString(id)); System.out.println(id); } } }
2021年12月08日
184 阅读
0 评论
0 点赞
1
...
10
11
12
...
20