增加Messaged.regexTopic
This commit is contained in:
@@ -73,11 +73,18 @@ public @interface Messaged {
|
|||||||
boolean required() default true;
|
boolean required() default true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 监听的topic
|
* 监听的topic, 当{@link #regexTopic() }值不为空时忽略此值
|
||||||
*
|
*
|
||||||
* @return topic
|
* @return topic
|
||||||
*/
|
*/
|
||||||
String[] topics();
|
String[] topics() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听的topic, 与 {@link #topics() }的值必须二选一,优先级高
|
||||||
|
*
|
||||||
|
* @return topic正则表达式
|
||||||
|
*/
|
||||||
|
String regexTopic() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息序列化类型
|
* 消息序列化类型
|
||||||
|
|||||||
@@ -71,11 +71,18 @@ public @interface ResourceConsumer {
|
|||||||
boolean required() default true;
|
boolean required() default true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 监听的topic
|
* 监听的topic, 当{@link #regexTopic() }值不为空时忽略此值
|
||||||
*
|
*
|
||||||
* @return topic
|
* @return topic
|
||||||
*/
|
*/
|
||||||
String[] topics();
|
String[] topics() default {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 监听的topic, 与 {@link #topics() }的值必须二选一,优先级高
|
||||||
|
*
|
||||||
|
* @return topic正则表达式
|
||||||
|
*/
|
||||||
|
String regexTopic() default "";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消息序列化类型
|
* 消息序列化类型
|
||||||
|
|||||||
25
src/main/java/org/redkale/mq/spi/DynForConsumer.java
Normal file
25
src/main/java/org/redkale/mq/spi/DynForConsumer.java
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.redkale.mq.spi;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import static java.lang.annotation.ElementType.TYPE;
|
||||||
|
import java.lang.annotation.Inherited;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 只标记给动态生成的MessageConsumer子类上
|
||||||
|
*
|
||||||
|
* @author zhangjx
|
||||||
|
*/
|
||||||
|
@Inherited
|
||||||
|
@Documented
|
||||||
|
@Target({TYPE})
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
public @interface DynForConsumer {
|
||||||
|
String group();
|
||||||
|
}
|
||||||
@@ -81,7 +81,10 @@ public abstract class MessageAgent implements MessageManager {
|
|||||||
protected final CopyOnWriteArrayList<MessageConsumer> messageConsumerList = new CopyOnWriteArrayList<>();
|
protected final CopyOnWriteArrayList<MessageConsumer> messageConsumerList = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
// key: group, sub-key: topic
|
// key: group, sub-key: topic
|
||||||
protected final Map<String, Map<String, MessageConsumerWrapper>> messageConsumerMap = new HashMap<>();
|
protected final Map<String, Map<String, MessageConsumerWrapper>> messageTopicConsumerMap = new HashMap<>();
|
||||||
|
|
||||||
|
// key: group, sub-key: regexTopic
|
||||||
|
protected final Map<String, Map<String, MessageConsumerWrapper>> messageRegexConsumerMap = new HashMap<>();
|
||||||
|
|
||||||
// -------------------------- HttpRpcClient、SncpMessageClient --------------------------
|
// -------------------------- HttpRpcClient、SncpMessageClient --------------------------
|
||||||
// cluster和mq同名组件时,HttpRpcClient优先使用MQ,默认不优先走MQ。
|
// cluster和mq同名组件时,HttpRpcClient优先使用MQ,默认不优先走MQ。
|
||||||
@@ -211,7 +214,8 @@ public abstract class MessageAgent implements MessageManager {
|
|||||||
consumer.destroy(config);
|
consumer.destroy(config);
|
||||||
}
|
}
|
||||||
this.messageConsumerList.clear();
|
this.messageConsumerList.clear();
|
||||||
this.messageConsumerMap.clear();
|
this.messageTopicConsumerMap.clear();
|
||||||
|
this.messageRegexConsumerMap.clear();
|
||||||
// -------------- MessageClient --------------
|
// -------------- MessageClient --------------
|
||||||
if (this.messageClientProducer != null) {
|
if (this.messageClientProducer != null) {
|
||||||
this.messageClientProducer.stop();
|
this.messageClientProducer.stop();
|
||||||
@@ -248,23 +252,31 @@ public abstract class MessageAgent implements MessageManager {
|
|||||||
final StringBuilder sb = new StringBuilder();
|
final StringBuilder sb = new StringBuilder();
|
||||||
clientConsumerLock.lock();
|
clientConsumerLock.lock();
|
||||||
try {
|
try {
|
||||||
Map<String, Map<String, MessageConsumerWrapper>> maps = new HashMap<>();
|
Map<String, Map<String, MessageConsumerWrapper>> topicMaps = new HashMap<>();
|
||||||
|
Map<String, Map<String, MessageConsumerWrapper>> regexMaps = new HashMap<>();
|
||||||
|
AtomicInteger groupMax = new AtomicInteger();
|
||||||
AtomicInteger typeMax = new AtomicInteger();
|
AtomicInteger typeMax = new AtomicInteger();
|
||||||
AtomicInteger topicMax = new AtomicInteger();
|
AtomicInteger topicMax = new AtomicInteger();
|
||||||
Map<String, String> views = new LinkedHashMap<>();
|
Map<String, String[]> views = new LinkedHashMap<>();
|
||||||
for (MessageConsumer consumer : consumers) {
|
for (MessageConsumer consumer : consumers) {
|
||||||
ResourceConsumer res = consumer.getClass().getAnnotation(ResourceConsumer.class);
|
ResourceConsumer res = consumer.getClass().getAnnotation(ResourceConsumer.class);
|
||||||
String group = environment.getPropertyValue(res.group());
|
String group = environment.getPropertyValue(res.group());
|
||||||
|
final String typeName =
|
||||||
|
Sncp.getResourceType((Class) consumer.getClass()).getName();
|
||||||
if (Utility.isBlank(group)) {
|
if (Utility.isBlank(group)) {
|
||||||
group = consumer.getClass().getName().replace('$', '.');
|
DynForConsumer dc = consumer.getClass().getAnnotation(DynForConsumer.class);
|
||||||
|
group = dc == null ? typeName.replace('$', '.') : dc.group();
|
||||||
}
|
}
|
||||||
Map<String, MessageConsumerWrapper> map = maps.computeIfAbsent(group, g -> new HashMap<>());
|
boolean regex = Utility.isNotEmpty(res.regexTopic());
|
||||||
|
Map<String, MessageConsumerWrapper> map =
|
||||||
|
(regex ? regexMaps : topicMaps).computeIfAbsent(group, g -> new HashMap<>());
|
||||||
List<String> topics = new ArrayList<>();
|
List<String> topics = new ArrayList<>();
|
||||||
for (String t : res.topics()) {
|
String[] ts = regex ? new String[] {res.regexTopic()} : res.topics();
|
||||||
String topic = environment.getPropertyValue(t);
|
for (String t : ts) {
|
||||||
if (!topic.trim().isEmpty()) {
|
String topic = environment.getPropertyValue(t).trim();
|
||||||
|
if (!topic.isEmpty()) {
|
||||||
topics.add(topic);
|
topics.add(topic);
|
||||||
if (map.containsKey(topic.trim())) {
|
if (map.containsKey(topic)) {
|
||||||
throw new RedkaleException(MessageConsumer.class.getSimpleName()
|
throw new RedkaleException(MessageConsumer.class.getSimpleName()
|
||||||
+ " consume topic (" + topic + ") repeat with "
|
+ " consume topic (" + topic + ") repeat with "
|
||||||
+ map.get(topic).getClass().getName() + " and "
|
+ map.get(topic).getClass().getName() + " and "
|
||||||
@@ -279,29 +291,39 @@ public abstract class MessageAgent implements MessageManager {
|
|||||||
+ ")");
|
+ ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
map.put(topic.trim(), new MessageConsumerWrapper(this, consumer, res.convertType()));
|
MessageConsumerWrapper wrapper =
|
||||||
|
new MessageConsumerWrapper(this, consumer, regex ? topic : null, res.convertType());
|
||||||
|
map.put(topic, wrapper);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String typestr = consumer.getClass().getName();
|
String typestr = typeName;
|
||||||
String topicstr = JsonConvert.root().convertTo(topics.size() == 1 ? topics.get(0) : topics);
|
String topicstr = JsonConvert.root().convertTo(topics.size() == 1 ? topics.get(0) : topics);
|
||||||
|
if (group.length() > groupMax.get()) {
|
||||||
|
groupMax.set(group.length());
|
||||||
|
}
|
||||||
if (typestr.length() > typeMax.get()) {
|
if (typestr.length() > typeMax.get()) {
|
||||||
typeMax.set(typestr.length());
|
typeMax.set(typestr.length());
|
||||||
}
|
}
|
||||||
if (topicstr.length() > topicMax.get()) {
|
if (topicstr.length() > topicMax.get()) {
|
||||||
topicMax.set(topicstr.length());
|
topicMax.set(topicstr.length());
|
||||||
}
|
}
|
||||||
views.put(typestr, topicstr);
|
views.put(typestr, new String[]{group, topicstr});
|
||||||
}
|
}
|
||||||
views.forEach((typestr, topicstr) -> {
|
views.forEach((typestr, strs) -> {
|
||||||
|
String groupstr = strs[0];
|
||||||
|
String topicstr = strs[1];
|
||||||
sb.append(MessageConsumer.class.getSimpleName())
|
sb.append(MessageConsumer.class.getSimpleName())
|
||||||
.append(" (type=")
|
.append(" (type=")
|
||||||
.append(alignString(typestr, typeMax.get()))
|
.append(alignString(typestr, typeMax.get()))
|
||||||
|
.append(", group=")
|
||||||
|
.append(alignString(groupstr, groupMax.get()))
|
||||||
.append(", topics=")
|
.append(", topics=")
|
||||||
.append(alignString(topicstr, topicMax.get()))
|
.append(alignString(topicstr, topicMax.get()))
|
||||||
.append(") startuped\r\n");
|
.append(") startuped\r\n");
|
||||||
});
|
});
|
||||||
messageConsumerList.addAll(consumers);
|
messageConsumerList.addAll(consumers);
|
||||||
messageConsumerMap.putAll(maps);
|
messageTopicConsumerMap.putAll(topicMaps);
|
||||||
|
messageRegexConsumerMap.putAll(regexMaps);
|
||||||
} finally {
|
} finally {
|
||||||
clientConsumerLock.unlock();
|
clientConsumerLock.unlock();
|
||||||
}
|
}
|
||||||
@@ -511,13 +533,17 @@ public abstract class MessageAgent implements MessageManager {
|
|||||||
|
|
||||||
private final Type messageType;
|
private final Type messageType;
|
||||||
|
|
||||||
public MessageConsumerWrapper(MessageAgent messageAgent, MessageConsumer<T> consumer, ConvertType convertType) {
|
private final String regexTopic;
|
||||||
|
|
||||||
|
public MessageConsumerWrapper(
|
||||||
|
MessageAgent messageAgent, MessageConsumer<T> consumer, String regexTopic, ConvertType convertType) {
|
||||||
Objects.requireNonNull(messageAgent);
|
Objects.requireNonNull(messageAgent);
|
||||||
Objects.requireNonNull(consumer);
|
Objects.requireNonNull(consumer);
|
||||||
Objects.requireNonNull(convertType);
|
Objects.requireNonNull(convertType);
|
||||||
this.messageAgent = messageAgent;
|
this.messageAgent = messageAgent;
|
||||||
this.convertType = convertType;
|
this.convertType = convertType;
|
||||||
this.consumer = consumer;
|
this.consumer = consumer;
|
||||||
|
this.regexTopic = regexTopic;
|
||||||
this.convert = ConvertFactory.findConvert(convertType);
|
this.convert = ConvertFactory.findConvert(convertType);
|
||||||
this.messageType = parseMessageType(consumer.getClass());
|
this.messageType = parseMessageType(consumer.getClass());
|
||||||
}
|
}
|
||||||
@@ -564,6 +590,10 @@ public abstract class MessageAgent implements MessageManager {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getRegexTopic() {
|
||||||
|
return regexTopic;
|
||||||
|
}
|
||||||
|
|
||||||
public MessageConsumer getConsumer() {
|
public MessageConsumer getConsumer() {
|
||||||
return consumer;
|
return consumer;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import org.redkale.annotation.AutoLoad;
|
import org.redkale.annotation.AutoLoad;
|
||||||
|
import org.redkale.annotation.Nonnull;
|
||||||
import org.redkale.asm.AnnotationVisitor;
|
import org.redkale.asm.AnnotationVisitor;
|
||||||
import org.redkale.asm.AsmMethodBean;
|
import org.redkale.asm.AsmMethodBean;
|
||||||
import org.redkale.asm.AsmMethodBoost;
|
import org.redkale.asm.AsmMethodBoost;
|
||||||
@@ -97,6 +98,14 @@ public class MessageAsmMethodBoost extends AsmMethodBoost {
|
|||||||
if (messaged == null) {
|
if (messaged == null) {
|
||||||
return newMethod;
|
return newMethod;
|
||||||
}
|
}
|
||||||
|
if (Utility.isEmpty(messaged.regexTopic()) && Utility.isEmpty(messaged.topics())) {
|
||||||
|
throw new RedkaleException(
|
||||||
|
"@" + Messaged.class.getSimpleName() + " regexTopic and topics both empty on " + method);
|
||||||
|
}
|
||||||
|
if (Utility.isNotEmpty(messaged.regexTopic()) && Utility.isNotEmpty(messaged.topics())) {
|
||||||
|
throw new RedkaleException(
|
||||||
|
"@" + Messaged.class.getSimpleName() + " regexTopic and topics both not empty on " + method);
|
||||||
|
}
|
||||||
if (!LoadMode.matches(remote, messaged.mode())) {
|
if (!LoadMode.matches(remote, messaged.mode())) {
|
||||||
return newMethod;
|
return newMethod;
|
||||||
}
|
}
|
||||||
@@ -157,8 +166,8 @@ public class MessageAsmMethodBoost extends AsmMethodBoost {
|
|||||||
|
|
||||||
protected void createInnerConsumer(
|
protected void createInnerConsumer(
|
||||||
ClassWriter pcw,
|
ClassWriter pcw,
|
||||||
Class serviceImplClass,
|
@Nonnull Class serviceImplClass,
|
||||||
Method method,
|
@Nonnull Method method,
|
||||||
Type messageType,
|
Type messageType,
|
||||||
Messaged messaged,
|
Messaged messaged,
|
||||||
String newDynName,
|
String newDynName,
|
||||||
@@ -168,7 +177,6 @@ public class MessageAsmMethodBoost extends AsmMethodBoost {
|
|||||||
final String innerClassName = "Dyn" + MessageConsumer.class.getSimpleName() + index.incrementAndGet();
|
final String innerClassName = "Dyn" + MessageConsumer.class.getSimpleName() + index.incrementAndGet();
|
||||||
final String innerFullName = newDynName + (pcw == null ? "" : "$") + innerClassName;
|
final String innerFullName = newDynName + (pcw == null ? "" : "$") + innerClassName;
|
||||||
final Class msgTypeClass = TypeToken.typeToClass(messageType);
|
final Class msgTypeClass = TypeToken.typeToClass(messageType);
|
||||||
final String msgTypeName = msgTypeClass.getName().replace('.', '/');
|
|
||||||
final String msgTypeDesc = org.redkale.asm.Type.getDescriptor(msgTypeClass);
|
final String msgTypeDesc = org.redkale.asm.Type.getDescriptor(msgTypeClass);
|
||||||
final String messageConsumerName = MessageConsumer.class.getName().replace('.', '/');
|
final String messageConsumerName = MessageConsumer.class.getName().replace('.', '/');
|
||||||
final String messageConsumerDesc = org.redkale.asm.Type.getDescriptor(MessageConsumer.class);
|
final String messageConsumerDesc = org.redkale.asm.Type.getDescriptor(MessageConsumer.class);
|
||||||
@@ -180,10 +188,9 @@ public class MessageAsmMethodBoost extends AsmMethodBoost {
|
|||||||
methodBeans = AsmMethodBoost.getMethodBeans(serviceType);
|
methodBeans = AsmMethodBoost.getMethodBeans(serviceType);
|
||||||
}
|
}
|
||||||
AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method);
|
AsmMethodBean methodBean = AsmMethodBean.get(methodBeans, method);
|
||||||
String methodSignature = null;
|
|
||||||
String genericMsgTypeDesc = msgTypeDesc;
|
String genericMsgTypeDesc = msgTypeDesc;
|
||||||
if (Utility.isNotEmpty(methodBean.getSignature())) {
|
if (Utility.isNotEmpty(methodBean.getSignature())) {
|
||||||
methodSignature = methodBean.getSignature();
|
String methodSignature = methodBean.getSignature();
|
||||||
methodSignature = methodSignature.substring(0, methodSignature.lastIndexOf(')') + 1) + "V";
|
methodSignature = methodSignature.substring(0, methodSignature.lastIndexOf(')') + 1) + "V";
|
||||||
int start = methodSignature.indexOf('<') + 1;
|
int start = methodSignature.indexOf('<') + 1;
|
||||||
genericMsgTypeDesc = methodSignature.substring(start, methodSignature.lastIndexOf('>')); // 获取<>中的值
|
genericMsgTypeDesc = methodSignature.substring(start, methodSignature.lastIndexOf('>')); // 获取<>中的值
|
||||||
@@ -206,6 +213,15 @@ public class MessageAsmMethodBoost extends AsmMethodBoost {
|
|||||||
Asms.visitAnnotation(av, ResourceConsumer.class, messaged);
|
Asms.visitAnnotation(av, ResourceConsumer.class, messaged);
|
||||||
av.visitEnd();
|
av.visitEnd();
|
||||||
}
|
}
|
||||||
|
{ // 设置DynForConsumer
|
||||||
|
AnnotationVisitor av = cw.visitAnnotation(org.redkale.asm.Type.getDescriptor(DynForConsumer.class), true);
|
||||||
|
String group = messaged.group();
|
||||||
|
if (Utility.isBlank(group)) {
|
||||||
|
group = serviceImplClass.getName().replace('$', '.');
|
||||||
|
}
|
||||||
|
av.visit("group", group);
|
||||||
|
av.visitEnd();
|
||||||
|
}
|
||||||
{ // 必须设置成@AutoLoad(false), 否则预编译打包后会被自动加载
|
{ // 必须设置成@AutoLoad(false), 否则预编译打包后会被自动加载
|
||||||
AnnotationVisitor av = cw.visitAnnotation(org.redkale.asm.Type.getDescriptor(AutoLoad.class), true);
|
AnnotationVisitor av = cw.visitAnnotation(org.redkale.asm.Type.getDescriptor(AutoLoad.class), true);
|
||||||
av.visit("value", false);
|
av.visit("value", false);
|
||||||
|
|||||||
@@ -286,6 +286,14 @@ public class MessageModuleEngine extends ModuleEngine {
|
|||||||
throw new RedkaleException("Not found " + MessageAgent.class.getSimpleName() + "(name = " + res.mq()
|
throw new RedkaleException("Not found " + MessageAgent.class.getSimpleName() + "(name = " + res.mq()
|
||||||
+ ") on " + clazz.getName());
|
+ ") on " + clazz.getName());
|
||||||
}
|
}
|
||||||
|
if (res != null && Utility.isEmpty(res.regexTopic()) && Utility.isEmpty(res.topics())) {
|
||||||
|
throw new RedkaleException("@" + ResourceConsumer.class.getSimpleName()
|
||||||
|
+ " regexTopic and topics both empty on " + clazz.getName());
|
||||||
|
}
|
||||||
|
if (res != null && Utility.isNotEmpty(res.regexTopic()) && Utility.isNotEmpty(res.topics())) {
|
||||||
|
throw new RedkaleException("@" + ResourceConsumer.class.getSimpleName()
|
||||||
|
+ " regexTopic and topics both not empty on " + clazz.getName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.allMessageConsumerEntrys = allEntrys;
|
this.allMessageConsumerEntrys = allEntrys;
|
||||||
logger.info("MessageAgent load MessageConsumer in " + (System.currentTimeMillis() - s) + " ms");
|
logger.info("MessageAgent load MessageConsumer in " + (System.currentTimeMillis() - s) + " ms");
|
||||||
|
|||||||
Reference in New Issue
Block a user