Using Redisson Distributed Locks with Custom Annotations in Java
This article explains how to apply Redisson's distributed lock in Java, demonstrates the basic lock and tryLock APIs, shows how to create a custom @DistributedLock annotation and an AOP aspect to handle locking automatically, and provides a practical usage example with two services.
In daily development, concurrent scenarios often require locking to ensure interface consistency; while local locks like ReentrantLock and synchronized are unsuitable for distributed systems, Redisson provides a reliable distributed lock implementation based on Redis.
2. Common Usage of Redisson Distributed Lock
Redisson implements the java.util.concurrent.locks.Lock interface. The basic lock acquisition pattern is shown below.
public void getLock() {
// Get lock
RLock lock = redisson.getLock("Lxlxxx_Lock");
try {
// 2. Acquire lock
lock.lock();
} catch (InterruptedException e) {
e.getStackTrace();
} finally {
// 3. Release lock
lock.unlock();
System.out.println("Finally,释放锁成功");
}
}Using lock.lock() can block indefinitely if the lock is not obtained, which is undesirable.
TryLock
The tryLock method returns a boolean, similar to ReentrantLock.tryLock. It attempts to acquire the lock and returns true on success, avoiding thread blockage; a failed attempt allows the program to continue with alternative logic. Redisson also includes a watchdog mechanism to automatically extend the lease of a near‑expiry lock.
RLock lock = redisson.getLock(name);
try {
if (lock.tryLock(2, 10, TimeUnit.SECONDS)) {
// Execute business logic
} else {
System.out.println("已存在");
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
// Release if current thread holds the lock
if (this.redissonLock.isHeldByCurrentThread(lockName)) {
this.redissonLock.unlock(lockName);
}
}3. Implementing Lock Mechanism with a Custom Annotation
To avoid repetitive lock code across methods, an AOP aspect can be used together with a custom annotation. The annotation definition is as follows:
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface DistributedLock {
String key() default "";
int leaseTime() default 10;
boolean autoRelease() default true;
String errorDesc() default "系统正常处理,请稍后提交";
int waitTime() default 1;
}The aspect class intercepts methods annotated with @DistributedLock, builds the lock key, attempts to acquire the lock, proceeds with the method execution, and finally releases the lock.
@Aspect
@Component
public class DistributedLockHandler {
private static final Logger log = LoggerFactory.getLogger(DistributedLockHandler.class);
@Autowired
RedissonLock redissonLock;
@Around("@annotation(distributedLock)")
public Object around(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable {
String lockName = this.getRedisKey(joinPoint, distributedLock);
int leaseTime = distributedLock.leaseTime();
String errorDesc = distributedLock.errorDesc();
int waitTime = distributedLock.waitTime();
Object result;
try {
boolean lock = this.redissonLock.tryLock(lockName, (long) leaseTime, (long) waitTime);
if (!lock) {
throw new RuntimeException(errorDesc);
}
result = joinPoint.proceed();
} catch (Throwable t) {
log.error("执行业务方法异常", t);
throw t;
} finally {
if (this.redissonLock.isHeldByCurrentThread(lockName)) {
this.redissonLock.unlock(lockName);
}
}
return result;
}
/**
* Generate the Redis key for the lock.
*/
private String getRedisKey(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) {
String key = distributedLock.key();
Object[] args = joinPoint.getArgs();
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
DefaultParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
String[] paramNames = nameDiscoverer.getParameterNames(method);
if (StringUtils.isEmpty(key)) {
if (paramNames != null && paramNames.length > 0) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < paramNames.length; i++) {
sb.append(paramNames[i]).append(" = ").append(args[i]);
}
key = sb.toString();
} else {
key = "redissionLock";
}
return key;
} else {
SpelExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression(key);
if (paramNames != null && paramNames.length != 0) {
EvaluationContext ctx = new StandardEvaluationContext();
for (int i = 0; i < paramNames.length; i++) {
ctx.setVariable(paramNames[i], args[i]);
}
try {
Object value = expression.getValue(ctx);
return (value != null && !"".equals(value.toString())) ? value.toString() : key;
} catch (Exception e) {
return key;
}
} else {
return key;
}
}
}
}4. Practical Usage
Apply the custom annotation to a method; the key attribute specifies the lock key and errorDesc provides the failure message. In the demo, two services (ports 8460 and 8461) are started; using Postman to call the same endpoint simultaneously shows that one service acquires the lock while the other fails the tryLock attempt, demonstrating the locking behavior.
5. Summary
Distributed locks should be used judiciously based on business requirements; for low concurrency scenarios they may be unnecessary, and excessive locking can degrade performance. In many B‑end projects, simple idempotent interfaces can avoid duplicate submissions without resorting to locks.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Architecture Digest
Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
