通常的接收mq消息都会根据topic来确定怎么处理该条消息,还有tag用来细分topic消息。在代码中用if else来判断topic和tag然后进行相应的处理。本文将使用java自定义注解来映射相对应的类,处理mq消息,用来代替难看的if else判断,并整合spring

1. 自定义注解

package cn.cxnxs.mq.annotation;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(value=ElementType.TYPE)

@Retention(value = RetentionPolicy.RUNTIME)

public @interface Topic {

	String value();

}

package cn.cxnxs.mq.annotation;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(value=ElementType.METHOD)

@Retention(value = RetentionPolicy.RUNTIME)

public @interface Tag {

	String value();

}

用这两个注解分别对应mq消息的topic和tag

2.mq消息处理类

package cn.cxnxs.mq.handler;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import cn.cxnxs.entity.Book;

import cn.cxnxs.mq.annotation.Tag;

import cn.cxnxs.mq.annotation.Topic;

import cn.cxnxs.mq.pojo.MQContext;

import cn.cxnxs.service.BookService;

@Service

@Topic("h1")

public class Handler1{

	

	@Autowired

	private BookService bookServiceImpl;

	

	@Tag("a")

	public void queryBook(MQContext context) {

		System.out.println("Handler1正在处理");

		//List<Book> s= bookServiceImpl.findBookById(1);

		//System.out.println(s);

	}

}

package cn.cxnxs.mq.handler;

import org.springframework.stereotype.Service;

import cn.cxnxs.mq.MQHandler;

import cn.cxnxs.mq.annotation.Tag;

import cn.cxnxs.mq.annotation.Topic;

import cn.cxnxs.mq.pojo.MQContext;

@Service

@Topic("h1")

public class Handler2 implements MQHandler{

	@Tag("*")

	public void Handler2Message(MQContext context) {

		System.out.println("Handler2正在处理");

	}

}

这两个处理类分别映射了topic=h1,tag=a这条mq消息,tag支持模糊匹配,Handler2中@Tag(*)代表匹配所有h1的tag.

3.处理类调用类

package cn.cxnxs.mq;

import java.io.File;

import java.lang.reflect.Method;

import java.util.ArrayList;

import java.util.List;

import java.util.regex.Pattern;

import org.apache.log4j.Logger;

import org.springframework.web.context.ContextLoader;

import org.springframework.web.context.WebApplicationContext;

import cn.cxnxs.mq.annotation.Tag;

import cn.cxnxs.mq.annotation.Topic;

import cn.cxnxs.mq.pojo.MQContext;

/**

 * 

 * 

 * <p>

 * Title: MQHandlerManager

 * </p>

 * 

 * <p>

 * Description:

 * </p>

 * 

 * @author potatomato

 * 

 * @date 2018年12月17日

 */

public class MQHandlerManager {

	private String packageName;

	private boolean isShowContent = false;

	private WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();;

	

	private Logger logger=Logger.getLogger(getClass());

	/**

	 * 执行类

	 */

	public void runHandler(MQContext context) {

		logger.info("开始扫描包[" + packageName + "]");

		List<String> classNames = getClassName(packageName);

		for (String className : classNames) {

			logger.info("MQ消息处理类:" + className);

		}

		if (isShowContent) {

			logger.info("消息标签:" + context.toString());

			logger.info("消息内容:" + context.getContent());

		}

		

		int count = 0;

		for (String className : classNames) {

			try {

				Class<?> handler = (Class<?>) Class.forName(className);

				if (handler.isAnnotationPresent(Topic.class)) {

					count++;

					Topic topic = (Topic) handler.getAnnotation(Topic.class);

					String topicVal=topic.value();

					if(topicVal.equals(context.getTopic())){

						Method[] methods=handler.getMethods();

						for (Method method:methods) {

							if(method.isAnnotationPresent(Tag.class)){

								Tag tag=method.getAnnotation(Tag.class);

	 							String tagStr=tag.value();

	 							String pattern = formatPattern(tagStr);

	 							boolean isMatch = Pattern.matches(pattern, context.getTag());

								if (isMatch) {

									String handlerName = bgCap2low(handler.getSimpleName());

									//从spring容器中获取对象

									method.invoke(webApplicationContext.getBean(handlerName),context);

								}

							}

						}

					}

				}

				

			} catch (ClassNotFoundException e) {

				// TODO Auto-generated catch block

				e.printStackTrace();

			} catch (Exception e) {

				// TODO Auto-generated catch block

				e.printStackTrace();

			}

			

		}

		if (count <= 0) {

			logger.info("消息" + context.toString() + "未匹配到处理类");

			return;

		}

	}

	/**

	 * 根据包名获取包下的所有类

	 * 

	 * @param packageName

	 * @return

	 */

	private List<String> getClassName(String packageName) {

		String filePath =this.getClass().getResource("/").getPath() + packageName.replace(".", "");

		

		List<String> fileNames = getClassName(filePath, null);

		return fileNames;

	}

	private List<String> getClassName(String filePath, List<String> className) {

		List<String> myClassName = new ArrayList<String>();

		File file = new File(filePath);

		File[] childFiles = file.listFiles();

		for (File childFile : childFiles) {

			if (childFile.isDirectory()) {

				myClassName.addAll(getClassName(childFile.getPath(), myClassName));

			} else {

				String childFilePath = childFile.getPath();

				childFilePath = childFilePath.substring(childFilePath.indexOf("classes") + 9,

						childFilePath.lastIndexOf("."));

				childFilePath = childFilePath.replace("", ".");

				myClassName.add(childFilePath);

			}

		}

		return myClassName;

	}

	private String formatPattern(String str) {

		str = str.replaceAll("*", ".*");

		return str;

	}

 

	/** 

	 * 把一个字符串的第一个字母小写

	 */

	private String bgCap2low(String fildeName) throws Exception {

		byte[] items = fildeName.getBytes(); 

		items[0] = (byte) ((char) items[0] - 'A' + 'a');

		return new String(items);

	}

	/**

	 * @return the packageName

	 */

	public String getPackageName() {

		return packageName;

	}

	/**

	 * @param packageName

	 *            the packageName to set

	 */

	public void setPackageName(String packageName) {

		this.packageName = packageName;

	}

	/**

	 * @return the isShowContent

	 */

	public boolean isShowContent() {

		return isShowContent;

	}

	/**

	 * @param isShowContent

	 *            the isShowContent to set

	 */

	public void setShowContent(boolean isShowContent) {

		this.isShowContent = isShowContent;

	}

}

将mq消息处理类放在固定的包里,扫描这个包中所有的类,循环判断类中是否用了@Topic注解,再执行这个类中@Tag注解的方法进行处理。

MQ消息封装类

package cn.cxnxs.mq.pojo;

public class MQContext {

	private String topic;

	private String tag;

	private String content;

	

	public MQContext(String topic,String tag,String content) {

		this.topic=topic;

		this.tag=tag;

		this.content=content;

	}

	

	/**

	 * @return the topic

	 */

	public String getTopic() {

		return topic;

	}

	/**

	 * @param topic the topic to set

	 */

	public void setTopic(String topic) {

		this.topic = topic;

	}

	/**

	 * @return the tag

	 */

	public String getTag() {

		return tag;

	}

	/**

	 * @param tag the tag to set

	 */

	public void setTag(String tag) {

		this.tag = tag;

	}

	

	@Override

	public String toString(){

		return "[topic="+topic+",tag="+tag+"]";

	}

	/**

	 * @return the content

	 */

	public String getContent() {

		return content;

	}

	/**

	 * @param content the content to set

	 */

	public void setContent(String content) {

		this.content = content;

	}

}

场景类

package cn.cxnxs.controller;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Controller;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.ResponseBody;

import cn.cxnxs.entity.Book;

import cn.cxnxs.mq.MQHandlerManager;

import cn.cxnxs.mq.pojo.MQContext;

import cn.cxnxs.service.BookService;

@Controller

public class BookController {

	@Autowired

	private BookService bookServiceImpl;

	@RequestMapping("/handler")

	@ResponseBody

	public String handler(){

		MQHandlerManager manager=new MQHandlerManager();

		manager.setPackageName("cn.cxnxs.mq.handler");

		manager.setShowContent(true);

		String topic="h1";

		String tag="a";

		String content="{name:'张三',age:20}";

		MQContext context=new MQContext(topic, tag, content);

		manager.runHandler(context);

		return "OK";

	} 

}

因为反射调用方法的时候用webApplicationContext获取的对象,所以要使用这套代码事先得搭建好springmvc,场景类这里就写了一个controller