Skip to content

Commit

Permalink
Merge pull request #5 from weihubeats/v_1.1.0_aop优化
Browse files Browse the repository at this point in the history
V 1.1.0 代码优化
  • Loading branch information
weihubeats authored Dec 31, 2021
2 parents bbc14c9 + f4a6c83 commit 752d199
Show file tree
Hide file tree
Showing 18 changed files with 282 additions and 110 deletions.
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,20 @@ General mq message idempotent deduplication framework, out of the box, supports
<dependency>
<groupId>io.github.weihubeats</groupId>
<artifactId>wh-mq-rocketmq</artifactId>
<version>1.0.8</version>
<version>1.0.9</version>
</dependency>
```
- gradle
```xml
implementation 'io.github.weihubeats:wh-mq-rocketmq:1.0.8'
implementation 'io.github.weihubeats:wh-mq-rocketmq:1.0.9'
```

##### aliyun ons-client
```xml
<dependency>
<groupId>io.github.weihubeats</groupId>
<artifactId>wh-mq-aliyun-rocketmq</artifactId>
<version>1.0.8</version>
<version>1.0.9</version>
</dependency>
```

Expand Down Expand Up @@ -73,6 +73,16 @@ implementation 'io.github.weihubeats:wh-mq-aliyun-rocketmq'


## 自定义配置

- 基于配置文件自动配置
```yaml
idempotent:
redisKey: "mq::unique::"
redisValue : "ss"
tryLockTime: 2
redisTimeOut: 3
```
- 基于JavaBean
```java
@Bean
public IdempotentConfig idempotentConfig() {
Expand All @@ -96,7 +106,7 @@ implementation 'io.github.weihubeats:wh-mq-aliyun-rocketmq'
<dependency>
<groupId>io.github.weihubeats</groupId>
<artifactId>wh-core</artifactId>
<version>1.0.8</version>
<version>1.0.9</version>
</dependency>
```

Expand Down Expand Up @@ -137,7 +147,7 @@ public class RocketMQMessageConverter implements MessageConverter<MessageExt> {
- 1.0.4 : 支持阿里云RocketMQ Client
- 1.0.5 : 新增支持开源RocketMQ Client,新增自动化配置 `IdempotentConfig.java`
- 1.0.6 : 优化重复消费重复投递问题,优化代码结构
- 1.0.8 : 优化redis key 过期时间
- 1.0.9 : 优化redis key 过期时间

## 未来版本

Expand Down
10 changes: 5 additions & 5 deletions README_en.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,20 +30,20 @@ Necessary condition
<dependency>
<groupId>io.github.weihubeats</groupId>
<artifactId>wh-mq-rocketmq</artifactId>
<version>1.0.8</version>
<version>1.0.9</version>
</dependency>
```
- gradle
```xml
implementation 'io.github.weihubeats:wh-mq-rocketmq:1.0.8'
implementation 'io.github.weihubeats:wh-mq-rocketmq:1.0.9'
```

##### aliyun ons-client
```xml
<dependency>
<groupId>io.github.weihubeats</groupId>
<artifactId>wh-mq-aliyun-rocketmq</artifactId>
<version>1.0.8</version>
<version>1.0.9</version>
</dependency>
```

Expand Down Expand Up @@ -99,7 +99,7 @@ Introduce dependencies
<dependency>
<groupId>io.github.weihubeats</groupId>
<artifactId>wh-core</artifactId>
<version>1.0.8</version>
<version>1.0.9</version>
</dependency>
```

Expand Down Expand Up @@ -142,7 +142,7 @@ The general idea of the current redis implementation is as follows
- 1.0.4 : Support Alibaba Cloud RocketMQ Client
- 1.0.5 : Added support for open source RocketMQ Client, and added automatic configuration `IdempotentConfig.java`
- 1.0.6 : Optimize the problem of repeated consumption and repeated delivery, and optimize the code structure
- 1.0.8 : Optimize the redis key expiration time
- 1.0.9 : Optimize the redis key expiration time

## Future version

Expand Down
3 changes: 1 addition & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<groupId>io.github.weihubeats</groupId>
<artifactId>wh-mq-Idempotent</artifactId>
<packaging>pom</packaging>
<version>1.0.8</version>
<version>1.0.9</version>

<name>mq-Idempotent</name>
<description>mq-Idempotent</description>
Expand All @@ -30,7 +30,6 @@
<spring-boot.version>2.1.3.RELEASE</spring-boot.version>
<logback.version>1.2.3</logback.version>
<project.version>1.0</project.version>
<spring.version>5.0.9.RELEASE</spring.version>
</properties>

<dependencyManagement>
Expand Down
9 changes: 1 addition & 8 deletions wh-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>wh-mq-Idempotent</artifactId>
<groupId>io.github.weihubeats</groupId>
<version>1.0.8</version>
<version>1.0.9</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down Expand Up @@ -41,13 +41,6 @@
</dependency>


<!--<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
<optional>true</optional>
</dependency>-->



</dependencies>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package com.mq.idempotent.core.aop;

import lombok.NonNull;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.AopUtils;
import org.springframework.aop.support.ComposablePointcut;
import org.springframework.aop.support.StaticMethodMatcher;
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.util.Assert;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
* @author : wh
* @date : 2021/12/30 17:58
* @description:
*/
public class MqIdempotentAnnotationAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {

private final Advice advice;

private final Pointcut pointcut;

private final Class<? extends Annotation> annotation;

public MqIdempotentAnnotationAdvisor(@NonNull MethodInterceptor advice,
@NonNull Class<? extends Annotation> annotation) {
this.advice = advice;
this.annotation = annotation;
this.pointcut = buildPointcut();
}

@Override
public Pointcut getPointcut() {
return this.pointcut;
}

@Override
public Advice getAdvice() {
return this.advice;
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if (this.advice instanceof BeanFactoryAware) {
((BeanFactoryAware) this.advice).setBeanFactory(beanFactory);
}
}

private Pointcut buildPointcut() {
Pointcut cpc = new AnnotationMatchingPointcut(annotation, true);
Pointcut mpc = new AnnotationMethodPoint(annotation);
return new ComposablePointcut(cpc).union(mpc);
}

/**
* In order to be compatible with the spring lower than 5.0
*/
private static class AnnotationMethodPoint implements Pointcut {

private final Class<? extends Annotation> annotationType;

public AnnotationMethodPoint(Class<? extends Annotation> annotationType) {
Assert.notNull(annotationType, "Annotation type must not be null");
this.annotationType = annotationType;
}

@Override
public ClassFilter getClassFilter() {
return ClassFilter.TRUE;
}

@Override
public MethodMatcher getMethodMatcher() {
return new AnnotationMethodMatcher(annotationType);
}

private static class AnnotationMethodMatcher extends StaticMethodMatcher {
private final Class<? extends Annotation> annotationType;

public AnnotationMethodMatcher(Class<? extends Annotation> annotationType) {
this.annotationType = annotationType;
}

@Override
public boolean matches(Method method, Class<?> targetClass) {
if (matchesMethod(method)) {
return true;
}
// Proxy classes never have annotations on their redeclared methods.
if (Proxy.isProxyClass(targetClass)) {
return false;
}
// The method may be on an interface, so let's check on the target class as well.
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
return (specificMethod != method && matchesMethod(specificMethod));
}

private boolean matchesMethod(Method method) {
return AnnotatedElementUtils.hasAnnotation(method, this.annotationType);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,31 @@
import com.mq.idempotent.core.annotation.Idempotent;
import com.mq.idempotent.core.model.IdempotentConfig;
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.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
* @author : wh
* @date : 2021/11/12 11:18
* @date : 2021/12/21 18:51
* @description:
*/
@Aspect
@Slf4j
@Component
public class MqIdempotentAop {

public class MqIdempotentAnnotationInterceptor implements MethodInterceptor {

private final RedissonClient redissonClient;

private final IdempotentConfig idempotentConfig;

private final MessageConverter messageConverter;


public MqIdempotentAop(RedissonClient redissonClient, IdempotentConfig idempotentConfig, MessageConverter messageConverter) {
public MqIdempotentAnnotationInterceptor(RedissonClient redissonClient, IdempotentConfig idempotentConfig, MessageConverter messageConverter) {
if (Objects.isNull(redissonClient)) {
throw new NullPointerException("redissonClient template is null");
}
Expand All @@ -46,26 +37,21 @@ public MqIdempotentAop(RedissonClient redissonClient, IdempotentConfig idempoten
}


@Pointcut("@annotation(com.mq.idempotent.core.annotation.Idempotent)")
public void ciderDistributedLockAspect() {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {

}
Method method = methodInvocation.getMethod();

@Around(value = "ciderDistributedLockAspect()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
//切点所在的类
MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
Method method = methodSignature.getMethod();
String returnTypeName = method.getReturnType().getName();
// 方法返回值仅支持 boolean void 返回值
boolean isVoid = returnTypeName.equalsIgnoreCase("void");
if (!isVoid && !returnTypeName.equalsIgnoreCase("boolean")) {
throw new Exception("method returnType is not boolean or void");
}
//方法参数
Object[] args = pjp.getArgs();
Object[] args = methodInvocation.getArguments();
Idempotent annotation = method.getAnnotation(Idempotent.class);
String msgID = messageConverter.getUniqueKey(Arrays.stream(args).findFirst().orElseThrow(() -> new Exception("参数异常")));
String msgID = messageConverter.getUniqueKey(Arrays.stream(args).findFirst().orElseThrow(() -> new Exception("仅支持第一个消息为Message")));
String key = idempotentConfig.getRedisKey() + msgID;
if (log.isDebugEnabled()) {
log.info("唯一key {}", key);
Expand All @@ -78,22 +64,28 @@ public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
log.info("有消息正在消费");
throw new Exception("有消息正在消费");
}
return proceed(methodInvocation, key);
}

public Object proceed(MethodInvocation methodInvocation, String key) {
try {
Object proceed = pjp.proceed();
Object proceed = methodInvocation.proceed();
RBucket<String> bucket = redissonClient.getBucket(key);
bucket.set(idempotentConfig.getRedisValue(), idempotentConfig.getRedisTimeOut(), TimeUnit.DAYS);
bucket.set(idempotentConfig.getRedisValue(), idempotentConfig.getRedisTimeOut(), idempotentConfig.getRedisTimeOutTimeUnit());
return proceed;
} catch (Throwable throwable) {
log.error("throwable ", throwable);
throw new RuntimeException(throwable);
} finally {
RLock stockLock = redissonClient.getLock(key);
stockLock.unlock();
}
}


public boolean lock(String lockName) {
RLock stockLock = redissonClient.getLock(lockName);
try {
return stockLock.tryLock(idempotentConfig.getTryLockTime(), TimeUnit.SECONDS);
return stockLock.tryLock(idempotentConfig.getTryLockTime(), idempotentConfig.getTryLockTimeUnit());
} catch (InterruptedException e) {
e.printStackTrace();
}
Expand All @@ -104,9 +96,4 @@ public boolean exitKey(String key) {
RBucket<String> stockLock = redissonClient.getBucket(key);
return stockLock.isExists();
}





}
Loading

0 comments on commit 752d199

Please sign in to comment.