All Projects → alturkovic → Distributed Lock

alturkovic / Distributed Lock

Licence: mit
Distributed locking with Spring

Programming Languages

java
68154 projects - #9 most used programming language

Labels

Projects that are alternatives of or similar to Distributed Lock

Springboot
📚 springboot学习记录
Stars: ✭ 119 (-7.03%)
Mutual labels:  spring
Ssm Demo
🍌Spring+SpringMVC+Mybatis+easyUI实现简单的后台管理系统
Stars: ✭ 1,639 (+1180.47%)
Mutual labels:  spring
Android Notes
Articles, notes, interview questions and resources management for Android.
Stars: ✭ 126 (-1.56%)
Mutual labels:  spring
Springactionmenu
This is a spring ActionMenu - 一个弹性的功能菜单
Stars: ✭ 120 (-6.25%)
Mutual labels:  spring
Spring Boot Blog
Simple blog web app made using Spring Boot + Thymeleaf
Stars: ✭ 121 (-5.47%)
Mutual labels:  spring
Mlds2018spring
Machine Learning and having it Deep and Structured (MLDS) in 2018 spring
Stars: ✭ 124 (-3.12%)
Mutual labels:  spring
Wicket Spring Boot
Spring Boot starter for Apache Wicket
Stars: ✭ 117 (-8.59%)
Mutual labels:  spring
Bucket4j Spring Boot Starter
Spring Boot Starter for Bucket4j
Stars: ✭ 127 (-0.78%)
Mutual labels:  spring
Downlords Faf Client
Official client for Forged Alliance Forever
Stars: ✭ 121 (-5.47%)
Mutual labels:  spring
Angular bootstrap spring
AngularJS, Restful, Spring, Spring Security, Hibernate,Bootstrap, Gulp in ES6, Maven
Stars: ✭ 125 (-2.34%)
Mutual labels:  spring
Fullstack Angular And Springboot
Source code for the popular course. Full Stack: Angular and Spring Boot
Stars: ✭ 121 (-5.47%)
Mutual labels:  spring
Securing Rest Api Spring Security
Spring Boot 2.2.x + Spring 5.2.x Rest Api Security Example
Stars: ✭ 117 (-8.59%)
Mutual labels:  spring
Spring Javafx Examples
Example apps for springboot-javafx-support. See
Stars: ✭ 124 (-3.12%)
Mutual labels:  spring
Extdirectspring
Implementation of the Ext Direct protocol with Java and Spring
Stars: ✭ 119 (-7.03%)
Mutual labels:  spring
Sfg Blog Posts
Source code examples for blog posts
Stars: ✭ 125 (-2.34%)
Mutual labels:  spring
Jstarcraft Example
基于JStarCraft RNS引擎,Spring Boot框架和公共数据集搭建的千人千面演示项目. 系统会根据用户的行为记录,自动调整用户的推荐内容和搜索内容.使用者可以通过该项目了解*推荐系统*与*搜索系统*的运作流程. 涵盖了个性化推荐与个性化搜索2个部分.
Stars: ✭ 119 (-7.03%)
Mutual labels:  spring
Houserentalsystem
🏠 房屋租赁系统,基于主流框架 SSM 的实战项目。
Stars: ✭ 122 (-4.69%)
Mutual labels:  spring
React Rebound
High-performance spring animations in React
Stars: ✭ 128 (+0%)
Mutual labels:  spring
Permission
一款带ui基于RBAC模型的可自由配置的原生的权限框架
Stars: ✭ 127 (-0.78%)
Mutual labels:  spring
Nimrod
Nimrod - 基于 Spring Boot 构建 的 Java Web 平台企业级单体应用快速开发框架,适合中小型项目的应用和开发。所采用的技术栈包括 Spring Boot、Spring、Spring Web MVC、MyBatis、Thymeleaf 等,遵守阿里巴巴 Java 开发规约,帮助养成良好的编码习惯。整体采用 RBAC ( Role-Based Access Control ,基于角色的访问控制),具有严格的权限控制模块,支持系统与模块分离开发。最后希望这个项目能够对你有所帮助。Nimrod 开发交流群:547252502(QQ 群)
Stars: ✭ 125 (-2.34%)
Mutual labels:  spring

= Distributed Lock

Distributed lock ensures your method cannot be run in parallel from multiple JVMs (cluster of servers, microservices, ...). It uses a common store to keep track of used locks and your method needs to acquire one or more locks to run.

By default, locks follow methods lifecycle.They are obtained at the start of the method and released at the end of the method. Manual controlling is supported and explained later in this document.

All locks acquired by lock implementations in this project will expire after 10 seconds, timeout after 1 second if unable to acquire lock and sleep for 50 ms between retries. These options are customizable per annotation.

== Using locks

To lock your methods you need to first enable locking as described in the previous section.

Spring https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/config/BeanPostProcessor.html[BeanPostProcessor] will handle all @Locked methods including their aliases. The type field describes which implementation of the lock to use. To prevent repeating yourself if you plan on using the same implementation (as most people usually will), I've added alias support. They wrap the @Locked annotation and define the type used.

Each lock needs to define a https://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html[SpEL] expression used to acquire the lock. To learn more about Spring aliases visit https://github.com/spring-projects/spring-framework/wiki/Spring-Annotation-Programming-Model[this] link.

=== Lock refresh

Locks can be refreshed automatically on a regular interval. This allows methods that occasionally need to run longer than their expiration. Refreshing the lock periodically prolongs the expiration of its key(s). This means that the lock cannot be acquired by another resource as long as the resource using the lock does not end successfully. In case the resource holding the lock fails unexpectedly without releasing the lock, the lock will expire according to the last expiration that was written (that the last refresh has set).

=== Manually controlled locks

Sometimes you might want lock to be acquired when calling a specific method and get released only when it expires (throttling).

To acquire a lock that doesn't get released automatically set manuallyReleased to true on @Locked annotation.

For more grained control (e.g., locking in the middle of the method and releasing later in the code), inject the lock in your service and acquire the lock manually.

==== Example

[source,java]

@Component public class Example {

@Qualifier("simpleRedisLock")
private Lock lock;

// other fields...

private void manuallyLocked() {
    // code before locking...

    final String token = lock.acquire(keys, storeId, expiration, retry, timeout);

    // check if you acquired a token
    if (StringUtils.isEmpty(token)) {
        throw new IllegalStateException("Lock not acquired!");
    }

    // code after locking...

    lock.release(keys, token, storeId);

    // code after releasing the lock...
}

}

=== Unsuccessful locks

If method cannot be locked, DistributedLockException will be thrown.

Method might not acquire the lock if:

. keys from SpEL expression cannot be resolved . another method acquired the lock . Lock implementation threw an exception

== Examples

Locking a method with the name aliased in the document called lock in MongoDB:

[source,java]

@MongoLocked(expression = "'aliased'", storeId = "lock") public void runLockedWithMongo() { // locked code }

Locking with multiple keys determined in runtime, use SpEL, for an example:

[source,java]

@RedisMultiLocked(expression = "T(com.example.MyUtils).getNamesWithId(#p0)") public void runLockedWithRedis(final int id) { // locked code }

This means that the runLockedWithRedis method will execute only if all keys evaluated by expression were acquired.

Locking with a custom lock implementation based on value of integer field count:

[source,java]

@Locked(type = MyCustomLock.class, expression = "getCount", prefix = "using:") public void runLockedWithMyCustomLock() { // locked code }

== Enabling locking

The project contains several configurations and annotations to help you enable locking and customize it.

To enable locking you must first include @EnableDistributedLock. This will import the configuration that will autoconfigure the https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/beans/factory/config/BeanPostProcessor.html[BeanPostProcessor] required for locking.

Project provides the following out-of-the-box lock implementations:

  • JDBC
  • Mongo
  • Redis

=== JDBC locks

JDBC locks are provided in the distributed-lock-jdbc project.

.Mongo lock implementations |=== |Implementation |Alias |Multiple key support

|SimpleJdbcLock |@JdbcLocked |No |===

Include @EnableJdbcDistributedLock to enable JDBC locks. This will also include @EnableDistributedLock for you.

[source,java]

@Configuration @EnableJdbcDistributedLock public class LockConfiguration { }

[NOTE]

Make sure you create the table and configure the table ID incrementer.

Example how to create table: [source, sql]

create table lock ( id int not null auto_increment primary key, lock_key varchar(255) unique, token varchar(255), expireAt timestamp, );

=== MongoDB locks

MongoDB locks are provided in the distributed-lock-mongo project.

.Mongo lock implementations |=== |Implementation |Alias |Multiple key support

|SimpleMongoLock |@MongoLocked |No |===

Include @EnableMongoDistributedLock to enable MongoDB locks. This will also include @EnableDistributedLock for you.

[source,java]

@Configuration @EnableMongoDistributedLock public class LockConfiguration { }

[NOTE]

Make sure you create TTL index in your @Locked#storeId() collection on expireAt field to enable lock expiration.

=== Redis locks

Redis locks are provided in the distributed-lock-redis project.

.Redis lock implementations |=== |Implementation |Alias |Multiple key support

|SimpleRedisLock |@RedisLocked |No

|MultiRedisLock |@RedisMultiLocked |Yes |===

Include @EnableRedisDistributedLock to enable Redis locks. This will also include @EnableDistributedLock for you.

[source,java]

@Configuration @EnableRedisDistributedLock public class LockConfiguration { }

== Importing into your project

=== Maven

Add the JitPack repository into your pom.xml.

[source,xml]

jitpack.io https://jitpack.io ----

JitPack builds multi-modules by appending the repo name in the groupId. To add the Redis dependency for an example, add the following under your <dependencies>:

[source,xml]

com.github.alturkovic.distributed-lock distributed-lock-redis [insert latest version here] ----

=== Compatibility

|=== |Version |Spring Boot version

|1.4.1 |2.4.3

|1.4.0 |2.2.7.RELEASE

|1.3.0 |2.2.7.RELEASE

|1.2.2 |2.1.0.RELEASE

|1.2.1 |2.1.0.RELEASE

|1.2.0 |2.1.0.RELEASE

|1.1.10 |2.0.4.RELEASE

|1.1.9 |2.0.4.RELEASE

|1.1.8 |2.0.4.RELEASE

|1.1.7 |2.0.3.RELEASE

|1.1.6 and lower |1.5.6.RELEASE

|===

== SpEL key generator

This is the default key generator the advice uses. If you wish to use your own, simply write your own and define it as a @Bean.

The default key generator has access to the currently executing context, meaning you can access your fields and methods from SpEL. It uses the https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/DefaultParameterNameDiscoverer.html[DefaultParameterNameDiscoverer] to discover parameter names, so you can access your parameters in several different ways:

  1. using p# syntax, where # is the position of the parameter, for an example: p0 for the first parameter
  2. using a# syntax, where # is the position of the parameter, for an example: a2 for the third parameter
  3. using the parameter name, for an example, #message -- REQUIRES -parameters compiler flag

A special variable named executionPath is used to define the method called. This is the default expression used to describe the annotated method.

All validated expressions that result in an Iterable or an array will be converted to List<String> and all other values will be wrapped with Collections.singletonList. Elements of Iterable or array will also be converted to Strings using the https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/convert/ConversionService.html[ConversionService]. Custom converters can be registered. More about Spring conversion can be found https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#core-convert[here].

For more examples, take a look at com.github.alturkovic.lock.key.SpelKeyGeneratorTest.

== Customization

If you want to use custom lock implementations, simply implement Lock interface and register it in a configuration. You can also create an alias for your lock so you don't have to specify @Locked type field.

== Changelog

Started tracking the changes since 1.2.0 so no changelogs available for earlier versions.

==== 1.4.1

  • CHANGE: Upgraded Spring Boot version to 2.4.3
  • CHANGE: Migrated test to JUnit 5
  • CHANGE: Migrated Redis tests to use Docker container
  • BUGFIX: Injecting the user-defined LockTypeResolver properly
  • BUGFIX: Fixed BeanPostProcessor initialization warning messages
  • BUGFIX: Minor javadoc fix

==== 1.4.0

  • CHANGE: Switched back to Java 1.8 from 11 since most projects don't yet use 11

==== 1.3.0

  • CHANGE: Updated Java from 1.8 to 11
  • CHANGE: Refactored lots of coupled code
  • CHANGE: Extracted lots of reusable components such as retriable locks for easier manual control of locks
  • BUGFIX: LockBeanPostProcessor will now fire after existing advisors to support transactional advisors

==== 1.2.2

  • CHANGE: Removed explicit ParameterNameDiscoverer from SpelKeyGenerator which now uses the one provided by the CachedExpressionEvaluator
  • CHANGE: Used AopUtils once and passed the evaluated method to SpelKeyGenerator so it doesn't have to evaluate the same thing as LockMethodInterceptor

==== 1.2.1

  • FEATURE: Lock refreshing has been added. Check the 'Lock refresh' chapter for more details
  • BUGFIX: @RedisMultiLocked was using #executionPath as prefix instead of an expression
  • BUGFIX: @RedisMultiLocked was using expiration and timeout in milliseconds instead of seconds

==== 1.2.0

  • FEATURE: Added a JavaDoc description to com.github.alturkovic.lock.Lock.release() method
  • CHANGE: Rearranged the parameters of the com.github.alturkovic.lock.Lock.release() method to be more consistent
  • CHANGE: Rearranged the parameters of the com.github.alturkovic.lock.jdbc.service.JdbcLockSingleKeyService methods to be more consistent
  • CHANGE: EvaluationConvertException and LockNotAvailableException now extend the DistributedLockException
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].