Nepxion Aquarius — это набор распределённых компонентов для приложений, основанный на Redis и Zookeeper. Он включает в себя:
Особенности:
Совместимость:
Для использования распределённой блокировки, кэширования, генератора уникальных идентификаторов и ограничителя скорости и потока необходимо добавить соответствующие зависимости в проект.
Распределённая блокировка:
<dependency>
<groupId>com.nepxion</groupId>
<artifactId>aquarius-lock-starter</artifactId>
<version>${aquarius.version}</version>
</dependency>
Распределённое кэширование:
<dependency>
<groupId>com.nepxion</groupId>
<artifactId>aquarius-cache-starter</artifactId>
<version>${aqurius.version}</version>
</dependency>
Генератор распределённых уникальных идентификаторов:
<dependency>
<groupId>com.nepxion</groupId>
<artifactId>aquarius-id-generator-starter</artifactId>
<version>${aquarius.version}</version>
</dependency>
Ограничитель скорости и потока:
<dependency>
<groupId>com.nepxion</groupId>
<artifactId>aquarius-limit-starter</artifactId>
<version>${aquarius.version}</version>
</dependency>
``` **Nepxion Aquarius Lock**
На основе Redisson (Redis), Curator (Zookeeper) и распределённой блокировки, построенной на Nepxion Matrix AOP framework, вы можете выбрать один из трёх компонентов блокировки для внедрения в ваше приложение.
**Примечание:**
* Аннотация Key поддерживает семантику SPEL Java8. Однако для интерфейса прокси-сервера необходимо включить параметр компиляции.
* Обратитесь к документации Nepxion Marix для настройки параметра компилятора "-parameters" в IDE и Maven.
**Введение:**
* Блокировка поддерживает как распределённую блокировку на основе Redisson и Curator, так и локальную блокировку ReentrantLock.
* Блокировка может поддерживать как обычную блокировку с повторным входом, так и блокировку чтения/записи с повторным входом. Обычная блокировка с повторным входом является взаимоисключающей, а блокировка чтения/записи должна использоваться попарно. При записи другие распределённые процессы/потоки не могут читать или записывать данные, при чтении другие распределённые процессы/потоки могут считывать данные, но не могут записывать их. Разрешено одновременное использование нескольких блокировок чтения, но только одна блокировка записи. Несколько блокировок чтения не являются взаимоисключающими, блокировка чтения и блокировка записи являются взаимоисключающими.
* Блокировка может поддерживать справедливую блокировку и несправедливую блокировку.
* Блокировка может поддерживаться как синхронное выполнение, так и асинхронное выполнение (асинхронный захват блокировки, синхронная блокировка).
* Блокировка может быть сброшена после удержания блокировки в течение определённого времени или может ожидать тайм-аута при удержании блокировки.
* Аннотации блокировки могут быть добавлены в интерфейс, класс реализации или класс без интерфейса.
* Описание аннотации:
* com.nepxion.aquarius.lock.annotation.Lock — обычная блокировка с повторным входом;
* com.nepxion.aquarius.lock.annotation.ReadLock — блокировка чтения с повторным входом;
* com.nepxion.aquarius.lock.annotation.WriteLock — блокировка записи с повторным входом.
* Параметры описания:
* name — имя блокировки;
* key — ключ блокировки. Полный путь ключа блокировки — это prefix + «_» + name + «_» + key, где prefix — значение пространства имён в config.propertie;
* leaseTime — время удержания блокировки, блокировка автоматически сбрасывается, если она удерживается дольше этого времени (поддерживается Redisson, не поддерживается Curator и локальная блокировка);
* waitTime — время ожидания при отсутствии блокировки (по умолчанию используется синхронный режим, поддерживается Redisson, не поддерживается Curator и локальная блокировка);
* async — использовать ли асинхронный режим выполнения блокировки (по умолчанию используется синхронный режим, Redisson поддерживает оба режима, Curator не поддерживает асинхронный режим, локальная блокировка не поддерживает асинхронный режим);
* fair — использовать ли справедливую блокировку (по умолчанию используется несправедливая блокировка, Redisson поддерживает только обычную блокировку с повторным входом, Curator не поддерживает справедливую блокировку, локальная блокировка поддерживает справедливую блокировку).
* Поскольку блокировка является блокировкой с повторным входом, она поддерживает кэширование и повторное использование.
* Компоненты блокировки используют изменение ссылок на промежуточные компоненты блокировки в Pom для быстрой замены распределённых блокировок.
* Поддерживает несколько методов развёртывания Redisson (например, одиночный компьютер, кластер, режим дозорного), а также поддерживает json и yaml (по умолчанию) два метода конфигурации. Для переключения метода развёртывания необходимо изменить соответствующий файл config-redisson.yaml.
* Реализует различные механизмы повтора для Curator (например, exponentialBackoffRetry, boundedExponentialBackoffRetry, retryNTimes, retryForever, retryUntilElapsed), которые можно переключать в файле конфигурации.
* Блокировка поддерживает два способа вызова: аннотированный способ и прямой вызов.
**Пример:**
Использование распределённой блокировки в качестве примера, дополнительные сведения см. в aquarius-spring-boot-example в com.nepxion.aquarius.example.lock.
Пример использования обычной распределённой блокировки:
Способ аннотации:
```java
package com.nepxion.aquarius.example.lock.service;
/**
* <p>Title: Nepxion Aquarius</p>
* <p>Description: Nepxion Aquarius</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import com.nepxion.aquarius.lock.annotation.Lock;
public interface MyService1 {
@Lock(name = "lock", key = "#id1 + \"-\" + #id2", leaseTime = 5000L, waitTime = 60000L, async = false, fair = false)
String doA(String id1, String id2);
String doB(String id1, String id2);
}
``` ```
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import com.nepxion.aquarius.example.lock.service.MyService1;
import com.nepxion.aquarius.example.lock.service.MyService2Impl;
import com.nepxion.aquarius.lock.annotation.EnableLock;
@SpringBootApplication
@EnableLock
@ComponentScan(basePackages = { "com.nepxion.aquarius.example.lock.service" })
public class LockAopApplication {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext applicationContext = SpringApplication.run(LockAopApplication.class, args);
// 执行效果是doA和doC无序打印,即谁拿到锁谁先运行
MyService1 myService1 = applicationContext.getBean(MyService1.class);
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
myService1.doA("X", "Y");
}
}).start();
}
MyService2Impl myService2 = applicationContext.getBean(MyService2Impl.class);
for (int i = 0; i < 5; i++) {
new Thread(new Runnable() {
@Override
public void run() {
myService2.doC("X", "Y");
}
}).start();
}
}
@Bean
public EmbeddedServletContainerFactory createEmbeddedServletContainerFactory() {
TomcatEmbeddedServletContainerFactory tomcatFactory = new TomcatEmbeddedServletContainerFactory();
tomcatFactory.setPort(8087);
return tomcatFactory;
}
}
``` **Использование распределённой блокировки для чтения и записи**
Код представляет собой фрагмент программы на языке Java, который демонстрирует использование распределённых блокировок для обеспечения параллельного доступа к общим ресурсам. Блокировки используются для предотвращения одновременного изменения одних и тех же данных несколькими потоками или процессами.
В коде создаются два интерфейса MyService3 и MyService4Impl с аннотациями @ReadLock и @WriteLock соответственно. Эти аннотации определяют параметры блокировки: имя, ключ, время аренды, время ожидания, асинхронность и справедливость. Затем в классе MyService4Impl реализуется метод doW, который выполняет операцию записи и использует блокировку для защиты общих данных.
Также в коде создаётся приложение, которое запускает несколько потоков, каждый из которых пытается получить блокировку. Если блокировка уже занята другим потоком, то текущий поток будет ждать освобождения блокировки. После получения блокировки поток выполняет свою задачу и затем освобождает блокировку.
**Примечание:** *данный перевод не является техническим и может содержать неточности.* ```
com.nepxion.aquarius.example.lock.service.MyService3;
import com.nepxion.aquarius.example.lock.service.MyService4Impl;
import com.nepxion.aquarius.lock.annotation.EnableLock;
@SpringBootApplication
@EnableLock
@ComponentScan(basePackages = { "com.nepxion.aquarius.example.lock.service" })
public class ReadWriteLockAopApplication {
private static final Logger LOG = LoggerFactory.getLogger(ReadWriteLockAopApplication.class);
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext applicationContext = SpringApplication.run(ReadWriteLockAopApplication.class, args);
// 执行效果是先打印doW,即拿到写锁,再打印若干个doR,即可以同时拿到若干个读��ку
MyService4Impl myService4 = applicationContext.getBean(MyService4Impl.class);
Timer timer1 = new Timer();
timer1.scheduleAtFixedRate(new TimerTask() {
public void run() {
LOG.info("Start to get write lock...");
// 写锁逻辑,最高持锁15秒,睡眠10秒,10秒后释放读��ку
myService4.doW("X", "Y");
}
}, 0L, 600000L);
MyService3 myService3 = applicationContext.getBean(MyService3.class);
Timer timer2 = new Timer();
timer2.scheduleAtFixedRate(new TimerTask() {
public void run() {
LOG.info("Start to get read lock...");
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
// 读��ку逻辑,最高持��ку5秒,睡眠2秒,2秒后释放读��ку
myService3.doR("X", "Y");
}
}).start();
}
}
}, 2000L, 2000L);
}
@Bean
public EmbeddedServletContainerFactory createEmbeddedServletContainerFactory() {
TomcatEmbeddedServletContainerFactory tomcatFactory = new TomcatEmbeddedServletContainerFactory();
tomcatFactory.setPort(8089);
return tomcatFactory;
}}
``` Таймер юнит миллисекондс снэп(10000л);
} catch (InterruptedException e) {
e.принтстэктрэйн();
}
лог точка инфо("ду ви ви - вит лок из гот");
}
} catch (Исключение е) {
е.принтстэктрэйн();
} наконец {
try {
лок экзекутор точка анлок(лок);
} catch (Exception e) {
e.принтстэктрэйн();
}}
}
}, 0л, 600000л);
таймер таймер2 = новый таймер();
таймер2 точка счидэйат фор фиксэд рэт(новый таймер таск() {
публик вун точка рун() {
лог точка инфо("старт ту гет рид лок...");
фор (инт я = 0; я < 3; я++) {
нью тирэд(новый ранэблэйбл() {
@переопределить
публик вонт точка рун() {
// рид лок логика, хайст вилд чойн рид лок 5 сек, снэп 2 сек, 2 сек пот вилд релиз рид лок
объект лок = нулл;
трай {
лок = лок экзекутор точка три лок(лок тип точка рид лок, "лок", "икс-уай", 5000л, 60000л, фэлсэ, фэлсэ);
иф (лок != нулл) {
трай {
тайм юнит точка миллисеконс снэп(2000л);
} катч (интерруптэдаблен е) {
е принтстэктрэйн();
}}
лог точка инфо("ду эр - рид лок из гот");
} кэтч (исключение е) {
е принтстэктрэйн();
}} наконец {
трай {
лок экзекутор точка анлок(лок);
} кэтч (исключение е) {
е принтстэк трэйн();
}}
}} точка старт();
}});
}}
}, 2000л, 2000л);
}
@бин
публик эмбэдэдэ сервлет кантейнер фэктори криэйат эмбэдэд сервлет кантейнер фэктори() {
томкат эмбэдэд сервлет кантейнер фэктори томкат фэктори = нью томкат эмбэдэд сервлет кантейнер фэктори();
томкат фэктори точка сэт порт(8090);
ретюрн томкат фэктори;
}
}
основан на Spring Redis для реализации, также можно изменить исходный код, чтобы заменить его на Redisson (в aquarius-cache-starter под CacheConfiguration, замените RedisCacheConfiguration на RedissonCacheConfiguration). Построен на Nepxion Matrix AOP framework.
Пример использования распределённого кэша: Одноключевое кэширование:
package com.nepxion.aquarius.example.cache.service;
/**
* <p>Title: Nepxion Aquarius</p>
* <p>Description: Nepxion Aquarius</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import com.nepxion.aquarius.cache.annotation.CacheEvict;
import com.nepxion.aquarius.cache.annotation.CachePut;
import com.nepxion.aquarius.cache.annotation.Cacheable;
public
``` ```
interface MyService5 {
@Cacheable(name = "cache", key = "#id1 + \"-\" + #id2", expire = -1L)
String doA(String id1, String id2);
@CachePut(name = "cache", key = "#id1 + \"-\" + #id2", expire = 60000L)
String doB(String id1, String id2);
@CacheEvict(name = "cache", key = "#id1 + \"-\" + #id2", allEntries = false, beforeInvocation = false)
String doC(String id1, String id2);
}
package com.nepxion.aquarius.example.cache.service;
/**
* <p>Title: Nepxion Aquarius</p>
* <p>Description: Nepxion Aquarius</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.nepxion.aquarius.cache.annotation.CacheEvict;
import com.nepxion.aquarius.cache.annotation.CachePut;
import com.nepxion.aquarius.cache.annotation.Cacheable;
@Service("myService6Impl")
public class MyService6Impl {
private static final Logger LOG = LoggerFactory.getLogger(MyService6Impl.class);
@Cacheable(name = "cache", key = {"#id1 + \"-\" + #id2", "abc"}, expire = -1L)
public String doD(String id1, String id2) {
try {
TimeUnit.MILLISECONDS.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
LOG.info("doD");
return "D";
}
@CachePut(name = "cache", key = {"#id1 + \"-\" + #id2", "abcde"}, expire = 60000L)
public String doE(String id1, String id2) {
try {
TimeUnit.MILLISECONDS.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
LOG.info("doE");
return "E";
}
@CacheEvict(name = "cache", key = {"#id1 + \"-\" + #id2", "abcdef"}, allEntries = true, beforeInvocation = false)
public String doF(String id1, String id2) {
try {
TimeUnit.MILLISECONDS.sleep(2000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
LOG.info("doF");
return "F";
}
}
``` ### Nepxion Aquarius ID Generator
#### Введение
- Поддержка последовательных номеров в Zookeeper для распределённого создания.
- Объект в узле Zookeeper имеет имя: "/" + prefix + "/" + name + "_" + key.
- Каждый распределённый объект получает уникальный номер, который увеличивается на 1.
- Поддержка уникальных номеров в Redis для распределённого создания.
- Ключ объекта в Redis имеет имя: prefix + "_" + name + "_" + key.
- Каждый распределённый объект получает уникальный номер, который соответствует правилам:
- Первые 17 цифр номера имеют формат yyyyMMddHHmmssSSS.
- Остальные цифры определяются значением length (максимум 8 цифр). Значение берётся из соответствующего ключа в Redis. Если длина меньше 8, то она дополняется нулями слева. Например, если значение в Redis равно 1234, а длина равна 2, то последние две цифры будут 34.
- Имитация распределённых номеров с использованием алгоритма SnowFlake, аналогичного тому, что используется в Twitter. Алгоритм генерирует 64-битные номера, которые можно использовать в распределённой системе. Номер состоит из следующих частей:
0 — 41 бит времени;
5 бит центра обработки данных;
5 бит машины;
12 бит порядкового номера.
```java
/**
* The class Snowflake id generator. Created by paascloud.net@gmail.com
* Twitter雪花ID算法
* 概述
* - SnowFlake算法是Twitter设计的一个可以在分布式系统中生成唯一的ID的算法,它可以满足Twitter每秒上万条消息ID分配的请求,这些消息ID是唯一的且有大致的递增顺序
*
* 原理
* - SnowFlake算法产生的ID是一个64位的整型,结构如下(每一部分用“-”符号分隔):
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000
* - 1位标识部分,在java中由于long的最高位是符号位,正数是0,负数是1,一般生成的ID为正数,所以为0
* - 41位时间戳部分,这个是毫秒级的时间,一般实现上不会存储当前的时间戳,而是时间戳的差值(当前时间-固定的开始时间),这样可以使产生的ID从更小值开始;41位的时间戳可以使用69年,(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年
* - 10位节点部分,Twitter实现中使用前5位作为数据中心标识,后5位作为机器标识,可以部署1024个节点
* - 12位序列号部分,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间戳)产生4096个ID序号,加起来刚好64位,为一个Long型
*
* 优点
* - SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右
*
* 使用
* - SnowFlake算法生成的ID大致上是按照时间递增的,用在分布式系统中时,需要注意数据中心标识和机器标识必须唯一,这样就能保证每个节点生成的ID都是唯一的。
* 或许我们不一定都需要像上面那样使用5位作为数据中心标识,5位作为机器标识,可以根据我们业务的需要,灵活分配节点部分,如:若不需要数据中心,完全可以使用全部10位作为机器标识;若数据中心不多,也可以只使用3位作为数据 центра,7位作为机器标识
*/
Пример использования ID Generator приведён ниже. Более подробную информацию см. в проекте aquarius-spring-boot-example в папке com.nepxion.aquarius.example.idgenerator.
package com.nepxion.aquarius.example.idgenerator.app2;
/**
* <p>Title: Nepxion Aquarius</p>
* <p>Description: Nepxion Aquarius</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import java.util.Timer;
import java.util.TimerTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import com.nepxion.aquarius.idgenerator.annotation.EnableRedisIdGenerator;
import com.nepxion.aquarius.idgenerator.redis.RedisIdGenerator;
@SpringBootApplication
@EnableRedisIdGenerator
public class RedisIdGeneratorApplication {
private static final Logger LOG = LoggerFactory.getLogger(RedisIdGeneratorApplication.class);
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext applicationContext = SpringApplication.run(RedisIdGeneratorApplication.class, args);
RedisIdGenerator redisIdGenerator = applicationContext.getBean(RedisIdGenerator.class);
Timer timer1 = new Timer();
timer1.scheduleAtFixedRate(new TimerTask() {
public void run() {
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
LOG.info("Timer1 - Unique id={}",
``` **Перевод кода на русский язык:**
redisIdGenerator.nextUniqueId("idgenerater", "X-Y", 1, 8));
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
}, 0L, 1000L);
Timer timer2 = new Timer();
timer2.scheduleAtFixedRate(new TimerTask() {
public void run() {
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
LOG.info("Timer2 - Unique id={}", redisIdGenerator.nextUniqueId("idgenerater", "X-Y", 1, 8));
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
}, 0L, 1500L);
Timer timer3 = new Timer();
timer3.scheduleAtFixedRate(new TimerTask() {
public void run() {
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
String[] ids = redisIdGenerator.nextUniqueIds("idgenerater", "X-Y", 1, 8, 10);
for (String id : ids) {
LOG.info("Timer3 - Unique id={}", id);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
}, 0L, 3000L);
}
@Bean
public EmbeddedServletContainerFactory createEmbeddedServletContainerFactory() {
TomcatEmbeddedServletContainerFactory tomcatFactory = new TomcatEmbeddedServletContainerFactory();
tomcatFactory.setPort(8083);
return tomcatFactory;
}
}
package com.nepxion.aquarius.example.idgenerator.app3;
/**
* <p>Title: Nepxion Aquarius</p>
* <p>Description: Nepxion Aquarius</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import java.util.Timer;
import java.util.TimerTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import com.nepxion.aquarius.idgenerator.annotation.EnableZookeeperIdGenerator;
import com.nepxion.aquarius.idgenerator.zookeeper.ZookeeperIdGenerator;
@SpringBootApplication
@EnableZookeeperIdGenerator
public class ZookeeperIdGeneratorApplication {
private static final Logger LOG = LoggerFactory.getLogger(ZookeeperIdGeneratorApplication.class);
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext applicationContext = SpringApplication.run(ZookeeperIdGeneratorApplication.class, args);
ZookeeperIdGenerator zookeeperIdGenerator = applicationContext.getBean(ZookeeperIdGenerator.class);
Timer timer1 = new Timer();
timer1.scheduleAtFixedRate(new TimerTask() {
public void run() {
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
LOG.info("Таймер 1 — Последовательность ID = {}", zookeeperIdGenerator.nextSequenceId("idgenerater", "X-Y"));
} catch (Exception e) {
``` **Перевод кода с английского языка на русский:**
Таймер timer1 = новый Timer();
timer1.scheduleAtFixedRate(новый TimerTask() {
public void run() {
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
LOG.info("Timer1 - Unique id={}", localIdGenerator.nextUniqueId(2, 3));
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
}, 0L, 1000L);
Таймер timer2 = новый Timer();
timer2.scheduleAtFixedRate(новый TimerTask() {
public void run() {
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
LOG.info("Timer2 - Sequence id={}", zookeeperIdGenerator.nextSequenceId("idgenerater", "X-Y"));
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
}, 0L, 1500L);
Таймер timer3 = новый Timer();
timer3.scheduleAtFixedRate(новый TimerTask() {
public void run() {
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
String[] ids = zookeeperIdGenerator.nextSequenceIds("idgenerater", "X-Y", 10);
for (String id : ids) {
LOG.info("Timer3 - Sequence id={}", id);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
}, 0L, 3000L);
}
@Bean
public EmbeddedServletContainerFactory createEmbeddedServletContainerFactory() {
TomcatEmbeddedServletContainerFactory tomcatFactory = new TomcatEmbeddedServletContainerFactory();
tomcatFactory.setPort(8084);
return tomcatFactory;
}
**Примечание:** в данном переводе могут быть неточности или ошибки, так как исходный код содержит фрагменты, которые не удалось перевести. Таймер timer2 = новый Timer();
timer2.scheduleAtFixedRate(новый TimerTask() {
public void run() {
for (int i = 0; i < 3; i++) {
новый поток(новый Runnable() {
@Override
public void run() {
try {
LOG.info("Timer2 - Unique id={}", localIdGenerator.nextUniqueId(2, 3));
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
}, 0L, 1500L);
Таймер timer3 = новый Timer();
timer3.scheduleAtFixedRate(новый TimerTask() {
public void run() {
for (int i = 0; i < 3; i++) {
новый поток(новый Runnable() {
@Override
public void run() {
try {
Строковый массив ids = localIdGenerator.nextUniqueIds(2, 3, 10);
for (Строка id : ids) {
LOG.info("Timer3 - Unique id={}", id);
}
} catch (Исключение e) {
e.printStackTrace();
}
}
}).start();
}
}
}, 0L, 3000L);
}
@Bean
public EmbeddedServletContainerFactory createEmbeddedServletContainerFactory() {
ТоматныйEmbeddedServletContainerFactory tomcatFactory = новый ТоматныйEmbeddedServletContainerFactory();
tomcatFactory.setPort(8082);
return tomcatFactory;
}
Nepxion Aquarius Limit
Пример использования Limit можно найти в проекте aquarius-spring-boot-example в папке com.nepxion.aquarius.example.limit.
package com.nepxion.aquarius.example.limit.service;
/**
* <p>Title: Nepxion Aquarius</p>
* <p>Description: Nepxion Aquarius</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import com.nepxion.aquarius.limit.annotation.Limit;
public interface MyService7 {
@Limit(name = "limit", key = "#id1 + \"-\" + #id2", limitPeriod = 10, limitCount = 5)
String doA(String id1, String id2);
}
package com.nepxion.aquarius.example.limit.service;
/**
* <p>Title: Nepxion Aquarius</p>
* <p>Description: Nepxion Aquarius</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.nepxion.aquarius.limit.annotation.Limit;
@Service("myService8Impl")
public class MyService8Impl {
private static final Logger LOG = LoggerFactory.getLogger(MyService8Impl.class);
@Limit(name = "limit", key = "#id1 + \"-\" + #id2", limitPeriod = 10, limitCount = 5)
public String doB(String id1, String id2) {
LOG.info("doB");
return "B";
}
}
``` ```
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import com.nepxion.aquarius.example.limit.service.MyService7;
import com.nepxion.aquarius.example.limit.service.MyService8Impl;
import com.nepxion.aquarius.limit.annotation.EnableLimit;
@SpringBootApplication
@EnableLimit
@ComponentScan(basePackages = { "com.nepxion.aquarius.example.limit.service" })
public class LimitAopApplication {
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext applicationContext = SpringApplication.run(LimitAopApplication.class, args);
MyService7 myService7 = applicationContext.getBean(MyService7.class);
Timer timer1 = new Timer();
timer1.scheduleAtFixedRate(new TimerTask() {
public void run() {
new Thread(new Runnable() {
@Override
public void run() {
myService7.doA("X", "Y");
}
}).start();
}
}, 0L, 3000L);
MyService8Impl myService8 = applicationContext.getBean(MyService8Impl.class);
Timer timer2 = new Timer();
timer2.scheduleAtFixedRate(new TimerTask() {
public void run() {
new Thread(new Runnable() {
@Override
public void run() {
myService8.doB("X", "Y");
}
}).start();
}
}, 0L, 4000L);
}
@Bean
public EmbeddedServletContainerFactory createEmbeddedServletContainerFactory() {
TomcatEmbeddedServletContainerFactory tomcatFactory = new TomcatEmbeddedServletContainerFactory();
tomcatFactory.setPort(8085);
return tomcatFactory;
}
}
package com.nepxion.aquarius.example.limit.app2;
/**
* <p>Title: Nepxion Aquarius</p>
* <p>Description: Nepxion Aquarius</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import java.util.Timer;
import java.util.TimerTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.embedded.EmbeddedServletContainerFactory;
import org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import com.nepxion.aquarius.limit.LimitExecutor;
import com.nepxion.aquarius.limit.annotation.EnableLimit;
@SpringBootApplication
@EnableLimit
@ComponentScan(basePackages = { "com.nepxion.aquarius.example.limit.service" })
public class LimitApplication {
private static final Logger LOG = LoggerFactory.getLogger(LimitApplication.class);
public static void main(String[] args) throws Exception {
ConfigurableApplicationContext applicationContext = SpringApplication.run(LimitApplication.class, args);
// 在给定的10秒里最多访问5次(超出次数返回false);等下个10秒开始,才允许再次被访问(返回true),周而复始
LimitExecutor limitExecutor = applicationContext.getBean(LimitExecutor.class);
Timer timer1 = new Timer();
timer1.scheduleAtFixedRate(new TimerTask() {
public void run() {
for (int i = 0; i < 3; i++) {
new Thread(new Runnable() {
@Override
public void run() {
try {
LOG.info("Timer1 - Limit={}", limitExecutor.tryAccess("limit", "X-Y", 10, 5));
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
}, 0L,
``` **Использование Nepxion Aquarius Spring Cloud**
### Введение
- Настройте сервер Euraka, в файле `aquarius-spring-cloud-example/src/main/resources/application.properties` измените на вашу локальную среду Eureka.
- Запустите AquariusApplication.
- Откройте Postman или браузер и выполните операцию Get, следуя приведённому ниже URL.
- Поддерживается Swagger, доступ по адресу: `http://localhost:2222/swagger-ui.html`.
#### Блокировка
* С использованием аннотаций:
`http://localhost:2222/doC?id1=X&id2=Y`
* Прямой вызов:
`http://localhost:2222/tryLock?lockType=WriteLock&name=lock&key=X-Y&leaseTime=5000&waitTime=60000&async=false&fair=false`
#### Кэш
* С использованием аннотаций:
`http://localhost:2222/doD?id1=X&id2=Y`
#### Лимит
* С использованием аннотаций:
`http://localhost:2222/doG?id1=X&id2=Y`
* Прямой вызов:
`http://localhost:2222/tryAccess?name=limit&key=A-B&limitPeriod=10&limitCount=5`
#### Генератор идентификаторов
* Прямой вызов (Redis):
`http://localhost:2222/nextUniqueId?name=idgenerater&key=X-Y&step=1&length=8`
* Прямой вызов (Zookeeper):
`http://localhost:2222/nextSequenceId?name=idgenerater&key=X-Y`
* Прямой вызов (алгоритм снежинки):
`http://localhost:2222/nextLocalUniqueId?dataCenterId=2&machineId=3`
## Свяжитесь со мной
Свяжитесь со мной через WeChat, DingTalk, официальный аккаунт или документацию.




## График популярности проекта Star
[](https://starchart.cc/Nepxion/Aquarius)
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )