java自定义注解运用
下面是用redis编写自定义注解实现进程锁:
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.hr360.redission.lock.aop.annonation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface UseRLock {
long maxLockTime() default 5000L;
String area() default "default";
String clazz() default "default";
String method() default "default";
UseRLock.LockPolicy policy() default UseRLock.LockPolicy.REJECT;
public static enum LockPolicy {
WAIT,
REJECT;
private LockPolicy() {
}
}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.hr360.redission.lock.aop.annonation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface LockKey {
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.hr360.redission.lock.aop;
public class RLockException extends RuntimeException {
public RLockException(String message) {
super(message);
}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.hr360.redission.lock.aop;
import com.hr360.commons.exception.hr360Exception;
import com.hr360.redission.lock.aop.annonation.LockKey;
import com.hr360.redission.lock.aop.annonation.UseRLock;
import com.hr360.redission.lock.aop.annonation.UseRLock.LockPolicy;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.concurrent.TimeUnit;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.StringUtils;
@Aspect
@Component
public class UseRLockAspect {
private static final String REDIS_NS = "rlock:";
private static final String DEFAULT = "default";
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
private RedissonClient redissonClient;
public UseRLockAspect() {
}
@AfterThrowing(
value = "@annotation(com.hr360.redission.lock.aop.annonation.UseRLock)",
throwing = "e"
)
public void afterThrowing(final JoinPoint joinPoint, Exception e) throws Throwable {
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
this.unlock(joinPoint);
} else {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
public void afterCompletion(int status) {
try {
UseRLockAspect.this.unlock(joinPoint);
} catch (NoSuchMethodException var3) {
UseRLockAspect.this.log.error("unlock:{}", var3);
}
}
});
}
}
@AfterReturning("@annotation(com.hr360.redission.lock.aop.annonation.UseRLock)")
public void after(final JoinPoint joinPoint) throws Throwable {
if (!TransactionSynchronizationManager.isSynchronizationActive()) {
this.unlock(joinPoint);
} else {
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
public void afterCommit() {
try {
UseRLockAspect.this.unlock(joinPoint);
} catch (NoSuchMethodException var2) {
UseRLockAspect.this.log.error("unlock:{}", var2);
}
}
});
}
}
private void unlock(JoinPoint joinPoint) throws NoSuchMethodException {
UseRLock annotation = this.getUseRLock(joinPoint);
String lockKey = this.getLockKey(annotation.area(), annotation.clazz(), annotation.method(), joinPoint);
RLock lock = this.redissonClient.getLock(lockKey);
if (lock != null && lock.isHeldByCurrentThread() && lock.isLocked()) {
lock.unlock();
}
}
@Around("@annotation(com.hr360.redission.lock.aop.annonation.UseRLock)")
public Object aroundMethod(ProceedingJoinPoint pjp) throws Throwable {
this.lock(pjp);
return pjp.proceed();
}
private void lock(ProceedingJoinPoint pjp) throws NoSuchMethodException {
UseRLock annotation = this.getUseRLock(pjp);
long maxLockTime = annotation.maxLockTime();
String area = annotation.area();
String clazz = annotation.clazz();
String method = annotation.method();
LockPolicy policy = annotation.policy();
RLock lock = null;
String lockKey = this.getLockKey(area, clazz, method, pjp);
lock = this.redissonClient.getLock(lockKey);
boolean locked = lock.isLocked();
if (locked && LockPolicy.REJECT.equals(policy)) {
throw new hr360Exception((String)null, "此业务调用仅允许一个并发处理");
} else {
lock.lock(maxLockTime, TimeUnit.MILLISECONDS);
}
}
private UseRLock getUseRLock(JoinPoint pjp) throws NoSuchMethodException {
Signature signature = pjp.getSignature();
MethodSignature mSignature = (MethodSignature)signature;
Class<?> declaringType = mSignature.getDeclaringType();
Method method = declaringType.getDeclaredMethod(mSignature.getName(), mSignature.getParameterTypes());
return (UseRLock)method.getAnnotation(UseRLock.class);
}
private String getLockKey(String area, String clazz, String methodName, JoinPoint pjp) throws NoSuchMethodException {
Signature signature = pjp.getSignature();
MethodSignature mSignature = (MethodSignature)signature;
Class<?> declaringType = mSignature.getDeclaringType();
Method method = declaringType.getDeclaredMethod(mSignature.getName(), mSignature.getParameterTypes());
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
if (parameterAnnotations != null && parameterAnnotations.length != 0) {
if ("default".equals(clazz)) {
clazz = declaringType.getName();
}
if ("default".equals(methodName)) {
methodName = method.getName();
}
Parameter[] parameters = method.getParameters();
Object[] args = pjp.getArgs();
StringBuilder lockKey = new StringBuilder();
lockKey.append("rlock:");
lockKey.append(area);
lockKey.append(":");
lockKey.append(clazz);
lockKey.append(":");
lockKey.append(methodName);
lockKey.append(":");
boolean hasLockKey = false;
for(int index = 0; index < args.length; ++index) {
Parameter parameter = parameters[index];
LockKey annotation = (LockKey)parameter.getAnnotation(LockKey.class);
if (annotation != null) {
Object arg = args[index];
String argStr = arg.toString();
if (arg == null || StringUtils.isEmpty(argStr)) {
throw new RLockException("@LockKey parameter must not be null");
}
hasLockKey = true;
lockKey.append(argStr);
}
}
if (!hasLockKey) {
throw new RLockException("@LockKey must be assigned");
} else {
return lockKey.toString();
}
} else {
throw new RLockException("@LockKey must be assigned");
}
}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.hr360.redisson.autoconfigure;
import java.time.Duration;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(
prefix = "hr360.redission.redis"
)
public class RedissionProperties {
private int database = 0;
private String url;
private String host = "localhost";
private String password;
private int port = 6379;
private boolean ssl;
private Duration timeout;
private RedissionProperties.Sentinel sentinel;
private RedissionProperties.Cluster cluster;
private final RedissionProperties.Jedis jedis = new RedissionProperties.Jedis();
private final RedissionProperties.Lettuce lettuce = new RedissionProperties.Lettuce();
public RedissionProperties() {
}
public int getDatabase() {
return this.database;
}
public void setDatabase(int database) {
this.database = database;
}
public String getUrl() {
return this.url;
}
public void setUrl(String url) {
this.url = url;
}
public String getHost() {
return this.host;
}
public void setHost(String host) {
this.host = host;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public int getPort() {
return this.port;
}
public void setPort(int port) {
this.port = port;
}
public boolean isSsl() {
return this.ssl;
}
public void setSsl(boolean ssl) {
this.ssl = ssl;
}
public void setTimeout(Duration timeout) {
this.timeout = timeout;
}
public Duration getTimeout() {
return this.timeout;
}
public RedissionProperties.Sentinel getSentinel() {
return this.sentinel;
}
public void setSentinel(RedissionProperties.Sentinel sentinel) {
this.sentinel = sentinel;
}
public RedissionProperties.Cluster getCluster() {
return this.cluster;
}
public void setCluster(RedissionProperties.Cluster cluster) {
this.cluster = cluster;
}
public RedissionProperties.Jedis getJedis() {
return this.jedis;
}
public RedissionProperties.Lettuce getLettuce() {
return this.lettuce;
}
public static class Pool {
private int maxIdle = 8;
private int minIdle = 0;
private int maxActive = 8;
private Duration maxWait = Duration.ofMillis(-1L);
public Pool() {
}
public int getMaxIdle() {
return this.maxIdle;
}
public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
}
public int getMinIdle() {
return this.minIdle;
}
public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
}
public int getMaxActive() {
return this.maxActive;
}
public void setMaxActive(int maxActive) {
this.maxActive = maxActive;
}
public Duration getMaxWait() {
return this.maxWait;
}
public void setMaxWait(Duration maxWait) {
this.maxWait = maxWait;
}
}
public static class Cluster {
private List<String> nodes;
private Integer maxRedirects;
public Cluster() {
}
public List<String> getNodes() {
return this.nodes;
}
public void setNodes(List<String> nodes) {
this.nodes = nodes;
}
public Integer getMaxRedirects() {
return this.maxRedirects;
}
public void setMaxRedirects(Integer maxRedirects) {
this.maxRedirects = maxRedirects;
}
}
public static class Sentinel {
private String master;
private List<String> nodes;
public Sentinel() {
}
public String getMaster() {
return this.master;
}
public void setMaster(String master) {
this.master = master;
}
public List<String> getNodes() {
return this.nodes;
}
public void setNodes(List<String> nodes) {
this.nodes = nodes;
}
}
public static class Jedis {
private RedissionProperties.Pool pool;
public Jedis() {
}
public RedissionProperties.Pool getPool() {
return this.pool;
}
public void setPool(RedissionProperties.Pool pool) {
this.pool = pool;
}
}
public static class Lettuce {
private Duration shutdownTimeout = Duration.ofMillis(100L);
private RedissionProperties.Pool pool;
public Lettuce() {
}
public Duration getShutdownTimeout() {
return this.shutdownTimeout;
}
public void setShutdownTimeout(Duration shutdownTimeout) {
this.shutdownTimeout = shutdownTimeout;
}
public RedissionProperties.Pool getPool() {
return this.pool;
}
public void setPool(RedissionProperties.Pool pool) {
this.pool = pool;
}
}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.hr360.redisson.autoconfigure;
import com.hr360.redisson.autoconfigure.RedissionProperties.Sentinel;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.ClusterServersConfig;
import org.redisson.config.Config;
import org.redisson.config.SentinelServersConfig;
import org.redisson.config.SingleServerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.util.ReflectionUtils;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan(
basePackages = {"com.hr360.redission.lock.aop"}
)
@ConditionalOnClass({Redisson.class, RedisOperations.class})
@AutoConfigureBefore({RedisAutoConfiguration.class})
@EnableConfigurationProperties({RedissionProperties.class})
public class RedissonAutoConfiguration {
private static final Logger log = LoggerFactory.getLogger(RedissonAutoConfiguration.class);
@Autowired
private RedissionProperties redissionProperties;
public RedissonAutoConfiguration() {
log.info("#### init RedissionAutoConfiguration success #### 20210306 Great");
}
@Bean(
destroyMethod = "shutdown"
)
@ConditionalOnMissingBean({RedissonClient.class})
public RedissonClient redisson() {
Config config = null;
Method clusterMethod = ReflectionUtils.findMethod(RedissionProperties.class, "getCluster");
Method timeoutMethod = ReflectionUtils.findMethod(RedissionProperties.class, "getTimeout");
Object timeoutValue = ReflectionUtils.invokeMethod(timeoutMethod, this.redissionProperties);
int timeout;
Method nodesMethod;
if (null == timeoutValue) {
timeout = 10000;
} else if (!(timeoutValue instanceof Integer)) {
nodesMethod = ReflectionUtils.findMethod(timeoutValue.getClass(), "toMillis");
timeout = ((Long)ReflectionUtils.invokeMethod(nodesMethod, timeoutValue)).intValue();
} else {
timeout = (Integer)timeoutValue;
}
if (this.redissionProperties.getSentinel() != null) {
nodesMethod = ReflectionUtils.findMethod(Sentinel.class, "getNodes");
Object nodesValue = ReflectionUtils.invokeMethod(nodesMethod, this.redissionProperties.getSentinel());
String[] nodes;
if (nodesValue instanceof String) {
nodes = this.convert(Arrays.asList(((String)nodesValue).split(",")));
} else {
nodes = this.convert((List)nodesValue);
}
config = new Config();
((SentinelServersConfig)config.useSentinelServers().setMasterName(this.redissionProperties.getSentinel().getMaster()).addSentinelAddress(nodes).setDatabase(this.redissionProperties.getDatabase()).setConnectTimeout(timeout)).setPassword(this.redissionProperties.getPassword());
} else {
Method method;
if (clusterMethod != null && ReflectionUtils.invokeMethod(clusterMethod, this.redissionProperties) != null) {
Object clusterObject = ReflectionUtils.invokeMethod(clusterMethod, this.redissionProperties);
method = ReflectionUtils.findMethod(clusterObject.getClass(), "getNodes");
List<String> nodesObject = (List)ReflectionUtils.invokeMethod(method, clusterObject);
String[] nodes = this.convert(nodesObject);
config = new Config();
((ClusterServersConfig)config.useClusterServers().addNodeAddress(nodes).setConnectTimeout(timeout)).setPassword(this.redissionProperties.getPassword());
} else {
config = new Config();
String prefix = "redis://";
method = ReflectionUtils.findMethod(RedissionProperties.class, "isSsl");
if (method != null && (Boolean)ReflectionUtils.invokeMethod(method, this.redissionProperties)) {
prefix = "rediss://";
}
((SingleServerConfig)((SingleServerConfig)config.useSingleServer().setAddress(prefix + this.redissionProperties.getHost() + ":" + this.redissionProperties.getPort()).setConnectTimeout(timeout)).setDatabase(this.redissionProperties.getDatabase()).setPassword(this.redissionProperties.getPassword())).setConnectionMinimumIdleSize(this.redissionProperties.getJedis().getPool().getMinIdle()).setConnectionPoolSize(this.redissionProperties.getJedis().getPool().getMaxActive());
}
}
return Redisson.create(config);
}
private String[] convert(List<String> nodesObject) {
List<String> nodes = new ArrayList(nodesObject.size());
Iterator var3 = nodesObject.iterator();
while(true) {
while(var3.hasNext()) {
String node = (String)var3.next();
if (!node.startsWith("redis://") && !node.startsWith("rediss://")) {
nodes.add("redis://" + node);
} else {
nodes.add(node);
}
}
return (String[])nodes.toArray(new String[nodes.size()]);
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>hr360-redisson-starter</artifactId>
<packaging>jar</packaging>
<version>2.8.221.fix</version>
<properties>
<org.redisson.version>3.12.4</org.redisson.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>4.0.0</version>
</dependency>
<!--<dependency>-->
<!--<groupId>org.springframework</groupId>-->
<!--<artifactId>spring-web</artifactId>-->
<!--</dependency>-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.2</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>