1:pom.xml添加依赖
< dependency> < groupId> org.redisson</ groupId> < artifactId> redisson-spring-boot-starter</ artifactId> < version> 3.21.1</ version>
</ dependency>
2-1:方法一:读取默认yml配置
spring : redis : database : 0 host : 127.0.0.1password : 123456 port : 6379
2-2:redisson.yml文件的方式
spring : redis : redisson : file : classpath: redisson.yml
2-3:redisson.yml
singleServerConfig : database : 0 address : redis: //127.0.0.1: 6379 password : 123456
clusterServersConfig : nodeAddresses : - "redis://127.0.0.1:16379" - "redis://127.0.0.1:26379" - "redis://127.0.0.1:36379" password : 123456
3-1:方法二:自定义yml配置
spring : redis : redisson : enabled : true mode : singleaddress : redis: //127.0.0.1: 6379 password : 123456 database : 0
3-2:RedissonConfig自定义配置类
import org. apache. commons. lang3. StringUtils ;
import org. redisson. Redisson ;
import org. redisson. api. RedissonClient ;
import org. redisson. config. Config ;
import org. springframework. beans. factory. annotation. Value ;
import org. springframework. boot. autoconfigure. condition. ConditionalOnProperty ;
import org. springframework. context. annotation. Bean ;
import org. springframework. context. annotation. Configuration ;
@Configuration
@ConditionalOnProperty ( name = "spring.redis.redisson.enabled" , havingValue = "true" )
public class RedissonConfig { @Value ( "${spring.redis.redisson.mode}" ) private String mode; @Value ( "${spring.redis.redisson.masterName:}" ) private String masterName; @Value ( "${spring.redis.redisson.address}" ) private String address; @Value ( "${spring.redis.redisson.password:}" ) private String password; @Value ( "${spring.redis.redisson.database:0}" ) private Integer database; @Bean public RedissonClient redissonClient ( ) { if ( StringUtils . isBlank ( password) ) { password = null ; } Config config = new Config ( ) ; if ( "single" . equals ( mode) ) { config. useSingleServer ( ) . setDatabase ( database) . setPassword ( password) . setAddress ( address) ; } else if ( "cluster" . equals ( mode) ) { String [ ] clusterAddresses = address. split ( "," ) ; config. useClusterServers ( ) . setPassword ( password) . addNodeAddress ( clusterAddresses) ; } else if ( "sentinel" . equals ( mode) ) { String [ ] sentinelAddresses = address. split ( "," ) ; config. useSentinelServers ( ) . setDatabase ( database) . setPassword ( password) . setMasterName ( masterName) . addSentinelAddress ( sentinelAddresses) ; } else if ( "master-slave" . equals ( mode) ) { String [ ] masterSlaveAddresses = address. split ( "," ) ; if ( masterSlaveAddresses. length == 1 ) { throw new IllegalArgumentException ( "redis.redisson.address MUST have multiple redis addresses for master-slave mode." ) ; } String [ ] slaveAddresses = new String [ masterSlaveAddresses. length - 1 ] ; System . arraycopy ( masterSlaveAddresses, 1 , slaveAddresses, 0 , slaveAddresses. length) ; config. useMasterSlaveServers ( ) . setDatabase ( database) . setPassword ( password) . setMasterAddress ( masterSlaveAddresses[ 0 ] ) . addSlaveAddress ( slaveAddresses) ; } else { throw new IllegalArgumentException ( mode) ; } return Redisson . create ( config) ; }
}
4:demo
@Resource private RedissonClient redissonClient; private static final String LOCK_KEY = "myLock" ; @SneakyThrows @GetMapping ( "test" ) public void test ( ) { RLock lock = redissonClient. getLock ( LOCK_KEY ) ; for ( int i = 0 ; i < 5 ; i++ ) { new Thread ( ( ) -> { try { lock. lock ( 10 , TimeUnit . SECONDS ) ; System . out. println ( new Date ( ) + Thread . currentThread ( ) . getName ( ) + " 获取到锁,开始处理任务..." ) ; Thread . sleep ( 2000 ) ; System . out. println ( new Date ( ) + Thread . currentThread ( ) . getName ( ) + " 处理任务完成,释放锁..." ) ; } catch ( InterruptedException e) { e. printStackTrace ( ) ; } finally { lock. unlock ( ) ; } } ) . start ( ) ; } Thread . sleep ( 10000 ) ; System . out. println ( "===" ) ; }
4-1:运行结果
5-1:自定义注解分布式锁JLock
package com. huan. study. mybatis. config ; import java. lang. annotation. * ; @Target ( { ElementType . TYPE , ElementType . METHOD } )
@Retention ( RetentionPolicy . RUNTIME )
@Documented
@Inherited
public @interface JLock { LockModel lockModel ( ) default LockModel . AUTO ; String [ ] lockKey ( ) default { } ; String keyConstant ( ) default "" ; long expireSeconds ( ) default 30000L ; long waitTime ( ) default 10000L ; String failMsg ( ) default "获取锁失败,请稍后重试" ;
}
5-2:LockModel
package com. huan. study. mybatis. config ;
public enum LockModel { REENTRANT , FAIR , MULTIPLE , REDLOCK , READ , WRITE , AUTO
}
5-3:BaseAspect
package com. huan. study. mybatis. aspect ; import lombok. extern. slf4j. Slf4j ;
import org. springframework. expression. EvaluationContext ;
import org. springframework. expression. Expression ;
import org. springframework. expression. ExpressionParser ;
import org. springframework. expression. spel. standard. SpelExpressionParser ;
import org. springframework. expression. spel. support. StandardEvaluationContext ; import java. util. ArrayList ;
import java. util. List ; @Slf4j
public class BaseAspect { public List < String > getValueBySpEL ( String key, String [ ] parameterNames, Object [ ] values, String keyConstant) { List < String > keys = new ArrayList < > ( ) ; if ( ! key. contains ( "#" ) ) { String s = "redis:lock:" + key + keyConstant; log. debug ( "lockKey:" + s) ; keys. add ( s) ; return keys; } ExpressionParser parser = new SpelExpressionParser ( ) ; EvaluationContext context = new StandardEvaluationContext ( ) ; for ( int i = 0 ; i < parameterNames. length; i++ ) { context. setVariable ( parameterNames[ i] , values[ i] ) ; } Expression expression = parser. parseExpression ( key) ; Object value = expression. getValue ( context) ; if ( value != null ) { if ( value instanceof List ) { List value1 = ( List ) value; for ( Object o : value1) { addKeys ( keys, o, keyConstant) ; } } else if ( value. getClass ( ) . isArray ( ) ) { Object [ ] obj = ( Object [ ] ) value; for ( Object o : obj) { addKeys ( keys, o, keyConstant) ; } } else { addKeys ( keys, value, keyConstant) ; } } log. info ( "表达式key={},value={}" , key, keys) ; return keys; } private void addKeys ( List < String > keys, Object o, String keyConstant) { keys. add ( "redis:lock:" + o. toString ( ) + keyConstant) ; }
}
5-4:DistributedLockHandler
package com. huan. study. mybatis. aspect ; import com. huan. study. mybatis. config. JLock ;
import com. huan. study. mybatis. config. LockModel ;
import lombok. SneakyThrows ;
import lombok. extern. slf4j. Slf4j ;
import org. aspectj. lang. ProceedingJoinPoint ;
import org. aspectj. lang. annotation. Around ;
import org. aspectj. lang. annotation. Aspect ;
import org. aspectj. lang. reflect. MethodSignature ;
import org. redisson. RedissonMultiLock ;
import org. redisson. RedissonRedLock ;
import org. redisson. api. RLock ;
import org. redisson. api. RedissonClient ;
import org. springframework. beans. factory. annotation. Autowired ;
import org. springframework. core. LocalVariableTableParameterNameDiscoverer ;
import org. springframework. stereotype. Component ; import java. util. ArrayList ;
import java. util. List ;
import java. util. concurrent. TimeUnit ;
@Slf4j
@Aspect
@Component
public class DistributedLockHandler extends BaseAspect { @Autowired ( required = false ) private RedissonClient redissonClient; @SneakyThrows @Around ( "@annotation(jLock)" ) public Object around ( ProceedingJoinPoint joinPoint, JLock jLock) { Object obj = null ; log. info ( "进入RedisLock环绕通知..." ) ; RLock rLock = getLock ( joinPoint, jLock) ; boolean res = false ; long expireSeconds = jLock. expireSeconds ( ) ; long waitTime = jLock. waitTime ( ) ; if ( rLock != null ) { try { if ( waitTime == - 1 ) { res = true ; rLock. lock ( expireSeconds, TimeUnit . MILLISECONDS ) ; } else { res = rLock. tryLock ( waitTime, expireSeconds, TimeUnit . MILLISECONDS ) ; } if ( res) { obj = joinPoint. proceed ( ) ; } else { log. error ( "获取锁异常" ) ; } } finally { if ( res) { rLock. unlock ( ) ; } } } log. info ( "结束RedisLock环绕通知..." ) ; return obj; } @SneakyThrows private RLock getLock ( ProceedingJoinPoint joinPoint, JLock jLock) { String [ ] keys = jLock. lockKey ( ) ; if ( keys. length == 0 ) { throw new RuntimeException ( "keys不能为空" ) ; } String [ ] parameterNames = new LocalVariableTableParameterNameDiscoverer ( ) . getParameterNames ( ( ( MethodSignature ) joinPoint. getSignature ( ) ) . getMethod ( ) ) ; Object [ ] args = joinPoint. getArgs ( ) ; LockModel lockModel = jLock. lockModel ( ) ; RLock rLock = null ; String keyConstant = jLock. keyConstant ( ) ; if ( lockModel. equals ( LockModel . AUTO ) ) { if ( keys. length > 1 ) { lockModel = LockModel . REDLOCK ; } else { lockModel = LockModel . REENTRANT ; } } if ( ! lockModel. equals ( LockModel . MULTIPLE ) && ! lockModel. equals ( LockModel . REDLOCK ) && keys. length > 1 ) { throw new RuntimeException ( "参数有多个,锁模式为->" + lockModel. name ( ) + ".无法锁定" ) ; } switch ( lockModel) { case FAIR : rLock = redissonClient. getFairLock ( getValueBySpEL ( keys[ 0 ] , parameterNames, args, keyConstant) . get ( 0 ) ) ; break ; case REDLOCK : List < RLock > rLocks = new ArrayList < > ( ) ; for ( String key : keys) { List < String > valueBySpEL = getValueBySpEL ( key, parameterNames, args, keyConstant) ; for ( String s : valueBySpEL) { rLocks. add ( redissonClient. getLock ( s) ) ; } } RLock [ ] locks = new RLock [ rLocks. size ( ) ] ; int index = 0 ; for ( RLock r : rLocks) { locks[ index++ ] = r; } rLock = new RedissonRedLock ( locks) ; break ; case MULTIPLE : rLocks = new ArrayList < > ( ) ; for ( String key : keys) { List < String > valueBySpEL = getValueBySpEL ( key, parameterNames, args, keyConstant) ; for ( String s : valueBySpEL) { rLocks. add ( redissonClient. getLock ( s) ) ; } } locks = new RLock [ rLocks. size ( ) ] ; index = 0 ; for ( RLock r : rLocks) { locks[ index++ ] = r; } rLock = new RedissonMultiLock ( locks) ; break ; case REENTRANT : List < String > valueBySpEL = getValueBySpEL ( keys[ 0 ] , parameterNames, args, keyConstant) ; if ( valueBySpEL. size ( ) == 1 ) { rLock = redissonClient. getLock ( valueBySpEL. get ( 0 ) ) ; } else { locks = new RLock [ valueBySpEL. size ( ) ] ; index = 0 ; for ( String s : valueBySpEL) { locks[ index++ ] = redissonClient. getLock ( s) ; } rLock = new RedissonRedLock ( locks) ; } break ; case READ : rLock = redissonClient. getReadWriteLock ( getValueBySpEL ( keys[ 0 ] , parameterNames, args, keyConstant) . get ( 0 ) ) . readLock ( ) ; break ; case WRITE : rLock = redissonClient. getReadWriteLock ( getValueBySpEL ( keys[ 0 ] , parameterNames, args, keyConstant) . get ( 0 ) ) . writeLock ( ) ; break ; } return rLock; }
}