java自定义注解处理mq消息

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

  1. 自定义注解


package cn.cxnxs.mq.annotation;\r\n\r\nimport java.lang.annotation.ElementType;\r\nimport java.lang.annotation.Retention;\r\nimport java.lang.annotation.RetentionPolicy;\r\nimport java.lang.annotation.Target;\r\n\r\n@Target(value=ElementType.TYPE)\r\n@Retention(value = RetentionPolicy.RUNTIME)\r\npublic @interface Topic {\r\n	String value();\r\n}\r\n\r\npackage cn.cxnxs.mq.annotation;\r\n\r\nimport java.lang.annotation.ElementType;\r\nimport java.lang.annotation.Retention;\r\nimport java.lang.annotation.RetentionPolicy;\r\nimport java.lang.annotation.Target;\r\n\r\n@Target(value=ElementType.METHOD)\r\n@Retention(value = RetentionPolicy.RUNTIME)\r\npublic @interface Tag {\r\n	String value();\r\n}

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

2.mq消息处理类

package cn.cxnxs.mq.handler;\r\n\r\nimport java.util.List;\r\n\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Service;\r\n\r\nimport cn.cxnxs.entity.Book;\r\nimport cn.cxnxs.mq.annotation.Tag;\r\nimport cn.cxnxs.mq.annotation.Topic;\r\nimport cn.cxnxs.mq.pojo.MQContext;\r\nimport cn.cxnxs.service.BookService;\r\n\r\n@Service\r\n@Topic("h1")\r\npublic class Handler1{\r\n	\r\n	@Autowired\r\n	private BookService bookServiceImpl;\r\n	\r\n	@Tag("a")\r\n	public void queryBook(MQContext context) {\r\n		System.out.println("Handler1正在处理");\r\n		//List<Book> s= bookServiceImpl.findBookById(1);\r\n		//System.out.println(s);\r\n	}\r\n}\r\npackage cn.cxnxs.mq.handler;\r\n\r\nimport org.springframework.stereotype.Service;\r\n\r\nimport cn.cxnxs.mq.MQHandler;\r\nimport cn.cxnxs.mq.annotation.Tag;\r\nimport cn.cxnxs.mq.annotation.Topic;\r\nimport cn.cxnxs.mq.pojo.MQContext;\r\n\r\n@Service\r\n@Topic("h1")\r\npublic class Handler2 implements MQHandler{\r\n\r\n	@Tag("*")\r\n	public void Handler2Message(MQContext context) {\r\n		System.out.println("Handler2正在处理");\r\n\r\n	}\r\n}

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

3.处理类调用类

package cn.cxnxs.mq;\r\n\r\nimport java.io.File;\r\nimport java.lang.reflect.Method;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\nimport java.util.regex.Pattern;\r\n\r\nimport org.apache.log4j.Logger;\r\nimport org.springframework.web.context.ContextLoader;\r\nimport org.springframework.web.context.WebApplicationContext;\r\n\r\nimport cn.cxnxs.mq.annotation.Tag;\r\nimport cn.cxnxs.mq.annotation.Topic;\r\nimport cn.cxnxs.mq.pojo.MQContext;\r\n\r\n/**\r\n * \r\n * \r\n * <p>\r\n * Title: MQHandlerManager\r\n * </p>\r\n * \r\n * <p>\r\n * Description:\r\n * </p>\r\n * \r\n * @author potatomato\r\n * \r\n * @date 2018年12月17日\r\n */\r\npublic class MQHandlerManager {\r\n\r\n	private String packageName;\r\n\r\n	private boolean isShowContent = false;\r\n\r\n	private WebApplicationContext webApplicationContext = ContextLoader.getCurrentWebApplicationContext();;\r\n	\r\n	private Logger logger=Logger.getLogger(getClass());\r\n	/**\r\n	 * 执行类\r\n	 */\r\n	public void runHandler(MQContext context) {\r\n\r\n		logger.info("开始扫描包[" + packageName + "]");\r\n		List<String> classNames = getClassName(packageName);\r\n		for (String className : classNames) {\r\n			logger.info("MQ消息处理类:" + className);\r\n		}\r\n		if (isShowContent) {\r\n			logger.info("消息标签:" + context.toString());\r\n			logger.info("消息内容:" + context.getContent());\r\n		}\r\n		\r\n		int count = 0;\r\n		for (String className : classNames) {\r\n			try {\r\n				Class<?> handler = (Class<?>) Class.forName(className);\r\n				if (handler.isAnnotationPresent(Topic.class)) {\r\n					count++;\r\n					Topic topic = (Topic) handler.getAnnotation(Topic.class);\r\n					String topicVal=topic.value();\r\n					if(topicVal.equals(context.getTopic())){\r\n						Method[] methods=handler.getMethods();\r\n						for (Method method:methods) {\r\n							if(method.isAnnotationPresent(Tag.class)){\r\n								Tag tag=method.getAnnotation(Tag.class);\r\n	 							String tagStr=tag.value();\r\n	 							String pattern = formatPattern(tagStr);\r\n	 							boolean isMatch = Pattern.matches(pattern, context.getTag());\r\n								if (isMatch) {\r\n									String handlerName = bgCap2low(handler.getSimpleName());\r\n									//从spring容器中获取对象\r\n									method.invoke(webApplicationContext.getBean(handlerName),context);\r\n								}\r\n							}\r\n						}\r\n					}\r\n				}\r\n				\r\n			} catch (ClassNotFoundException e) {\r\n				// TODO Auto-generated catch block\r\n				e.printStackTrace();\r\n			} catch (Exception e) {\r\n				// TODO Auto-generated catch block\r\n				e.printStackTrace();\r\n			}\r\n			\r\n		}\r\n\r\n		if (count <= 0) {\r\n			logger.info("消息" + context.toString() + "未匹配到处理类");\r\n			return;\r\n		}\r\n	}\r\n\r\n	/**\r\n	 * 根据包名获取包下的所有类\r\n	 * \r\n	 * @param packageName\r\n	 * @return\r\n	 */\r\n	private List<String> getClassName(String packageName) {\r\n		String filePath =this.getClass().getResource("/").getPath() + packageName.replace(".", "\\\\");\r\n		\r\n		List<String> fileNames = getClassName(filePath, null);\r\n		return fileNames;\r\n	}\r\n\r\n	private List<String> getClassName(String filePath, List<String> className) {\r\n		List<String> myClassName = new ArrayList<String>();\r\n		File file = new File(filePath);\r\n		File[] childFiles = file.listFiles();\r\n		for (File childFile : childFiles) {\r\n			if (childFile.isDirectory()) {\r\n				myClassName.addAll(getClassName(childFile.getPath(), myClassName));\r\n			} else {\r\n				String childFilePath = childFile.getPath();\r\n				childFilePath = childFilePath.substring(childFilePath.indexOf("\\\\classes") + 9,\r\n						childFilePath.lastIndexOf("."));\r\n				childFilePath = childFilePath.replace("\\\\", ".");\r\n				myClassName.add(childFilePath);\r\n			}\r\n		}\r\n		return myClassName;\r\n	}\r\n\r\n	private String formatPattern(String str) {\r\n		str = str.replaceAll("\\\\*", "\\\\.\\\\*");\r\n		return str;\r\n	}\r\n \r\n	/** \r\n	 * 把一个字符串的第一个字母小写\r\n	 */\r\n	private String bgCap2low(String fildeName) throws Exception {\r\n		byte[] items = fildeName.getBytes(); \r\n		items[0] = (byte) ((char) items[0] - 'A' + 'a');\r\n		return new String(items);\r\n	}\r\n\r\n	/**\r\n	 * @return the packageName\r\n	 */\r\n	public String getPackageName() {\r\n		return packageName;\r\n	}\r\n\r\n	/**\r\n	 * @param packageName\r\n	 *            the packageName to set\r\n	 */\r\n	public void setPackageName(String packageName) {\r\n		this.packageName = packageName;\r\n	}\r\n\r\n	/**\r\n	 * @return the isShowContent\r\n	 */\r\n	public boolean isShowContent() {\r\n		return isShowContent;\r\n	}\r\n\r\n	/**\r\n	 * @param isShowContent\r\n	 *            the isShowContent to set\r\n	 */\r\n	public void setShowContent(boolean isShowContent) {\r\n		this.isShowContent = isShowContent;\r\n	}\r\n\r\n}

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

MQ消息封装类

package cn.cxnxs.mq.pojo;\r\n\r\npublic class MQContext {\r\n\r\n	private String topic;\r\n	private String tag;\r\n	private String content;\r\n	\r\n	public MQContext(String topic,String tag,String content) {\r\n		this.topic=topic;\r\n		this.tag=tag;\r\n		this.content=content;\r\n	}\r\n	\r\n	/**\r\n	 * @return the topic\r\n	 */\r\n	public String getTopic() {\r\n		return topic;\r\n	}\r\n	/**\r\n	 * @param topic the topic to set\r\n	 */\r\n	public void setTopic(String topic) {\r\n		this.topic = topic;\r\n	}\r\n	/**\r\n	 * @return the tag\r\n	 */\r\n	public String getTag() {\r\n		return tag;\r\n	}\r\n	/**\r\n	 * @param tag the tag to set\r\n	 */\r\n	public void setTag(String tag) {\r\n		this.tag = tag;\r\n	}\r\n	\r\n	@Override\r\n	public String toString(){\r\n		return "[topic="+topic+",tag="+tag+"]";\r\n	}\r\n	/**\r\n	 * @return the content\r\n	 */\r\n	public String getContent() {\r\n		return content;\r\n	}\r\n	/**\r\n	 * @param content the content to set\r\n	 */\r\n	public void setContent(String content) {\r\n		this.content = content;\r\n	}\r\n}

场景类

package cn.cxnxs.controller;\r\n\r\nimport java.util.List;\r\n\r\nimport org.springframework.beans.factory.annotation.Autowired;\r\nimport org.springframework.stereotype.Controller;\r\nimport org.springframework.web.bind.annotation.RequestMapping;\r\nimport org.springframework.web.bind.annotation.ResponseBody;\r\n\r\nimport cn.cxnxs.entity.Book;\r\nimport cn.cxnxs.mq.MQHandlerManager;\r\nimport cn.cxnxs.mq.pojo.MQContext;\r\nimport cn.cxnxs.service.BookService;\r\n\r\n@Controller\r\npublic class BookController {\r\n\r\n	@Autowired\r\n	private BookService bookServiceImpl;\r\n\r\n	@RequestMapping("/handler")\r\n	@ResponseBody\r\n	public String handler(){\r\n		MQHandlerManager manager=new MQHandlerManager();\r\n		manager.setPackageName("cn.cxnxs.mq.handler");\r\n		manager.setShowContent(true);\r\n		String topic="h1";\r\n		String tag="a";\r\n		String content="{name:'张三',age:20}";\r\n		MQContext context=new MQContext(topic, tag, content);\r\n		manager.runHandler(context);\r\n		return "OK";\r\n	} \r\n}
因为反射调用方法的时候用webApplicationContext获取的对象,所以要使用这套代码事先得搭建好springmvc,场景类这里就写了一个controller 

本文标题:《java自定义注解处理mq消息》作者:mengjinyuan
原文链接:http://blog.cxnxs.cn/?id=91
特别注明外均为原创,转载请注明。

分享到微信

扫描二维码

可在微信查看或分享至朋友圈。

相关文章

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。