序:对于注解的认知是从spring开始的,不管是aop还是ioc,对于其概念是比较清楚的,但真正的实现却没有一个比较好的认知,前段时间看了下《从零开始写web框架》,但当时看的比较仓促,再说因为时间的原因,并没有细揪很多东西,这两天研究了下公司一个系统的代码,突然间对于这块有了比较好的理解,故做潦草记录。
项目使用自定义注解和反射主要是为了在webSocket请求发过来的时候,通过请求中的参数定位到类和方法,然后去执行具体的业务逻辑,具体整个流程如下。
1、自定义注解
@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface SocketCommand { /** * 请求的命令号 * @return */ short cmd();}
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface SocketModule { /** * 请求的模块号 * @return */ short module();}第一个注解配置在方法上,第二个注解配置到类上。2、利用BeanPostProcessor类中的postProcessAfterInitialization方法,在实例化类之后开始做注解扫描。
@Componentpublic class HandlerScanner implements BeanPostProcessor{ private Logger logger = Logger.getLogger(HandlerScanner.class); @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { Class<? extends Object> clazz = bean.getClass(); Class<?>[] interfaces = clazz.getInterfaces(); if(interfaces != null && interfaces.length>0){ for (Class<?> interFace :interfaces){ SocketModule socketModule = interFace.getAnnotation(SocketModule.class);--获取类注解 if (socketModule == null){ continue; } Method[] methods = interFace.getMethods(); if(methods != null && methods.length>0){ for (Method method:methods){ SocketCommand socketCommand = method.getAnnotation(SocketCommand.class);--获取自定义方法注解 if (socketCommand == null){ continue; } short module = socketModule.module(); short cmd = socketCommand.cmd(); try { if (InvokerHoler.getInvoker(module,cmd)==null){ InvokerHoler.addInvoker(module,cmd, Invoker.valueOf(method,bean));--将符合条件的加入到map中 }else { logger.error("重复命令:"+"module:"+module+" "+"cmd: "+cmd); } } catch (Exception e) { logger.error("获取失败: "+e.getMessage()); } } } } } return bean; }}附录InvokerHoler:
public class InvokerHoler { /** * 命令调用器 */ private static Map<Short,Map<Short,Invoker>> invokers = new HashMap<Short, Map<Short, Invoker>>(); /** * 添加命令调用 * @param module * @param cmd * @param invoker */ public static void addInvoker(short module,short cmd,Invoker invoker){ Map<Short , Invoker> map = invokers.get(module); if(map == null){ map = new HashMap<Short, Invoker>(); invokers.put(module,map); } map.put(cmd,invoker); } /** * 获取命令调用 * @param module * @param cmd * @return * @throws Exception */ public static Invoker getInvoker(Short module,Short cmd)throws Exception{ Invoker invoker = null; Map<Short,Invoker> map = invokers.get(module); if(map!=null){ invoker = map.get(cmd); } return invoker; }}附录Invoker:
public class Invoker { private Logger logger = Logger.getLogger(Invoker.class); /** * 方法 */ private Method method; /** * 目标对象 */ private Object target; /** * 获取实体类 * @param method * @param target * @return */ public static Invoker valueOf(Method method,Object target){ Invoker invoker = new Invoker(); invoker.setMethod(method); invoker.setTarget(target); return invoker; } public Object invoke(Object... paramValues){ try { return method.invoke(target,paramValues); } catch (IllegalAccessException e) { logger.error(e.getMessage()); } catch (InvocationTargetException e) { logger.error(e.getMessage()); } return null; } public void setMethod(Method method) { this.method = method; } public void setTarget(Object target) { this.target = target; } public Method getMethod() { return method; } public Object getTarget() { return target; }}3、第二步的操作相当于已经把所有自定义注解表标识的类放入到了map中,map的结构为Map<Short,Map<Short,Invoker>>,此时在webscoket连链接中获取传入的参数,并寻找指定的方法。
@Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame frame) throws Exception { SessionImpl session = new SessionImpl(ctx.channel()); Channel channel = ctx.channel(); String request = frame.text(); logger.debug("收到信息:"+request); WebSocketRequest webSocketRequest = JsonUtils.readValue(request, WebSocketRequest.class); checkParameters(webSocketRequest); Invoker invoker = InvokerHoler.getInvoker(webSocketRequest.getModule(), webSocketRequest.getCmd());--获取执行方法 if (invoker == null){ throw new Exception("没有找到相应的执行器"); } invoker.invoke(session,webSocketRequest);执行方法 附录MsgHandler:
@SocketModule(module = 1)public interface MsgHandler { @SocketCommand(cmd = 1) void sendMessage(Session session,Object message) throws Exception;}链接数据: ‘{"version":"1","module":1,"cmd":1,"data":"‘+message+‘"}‘;通过Moudlue和cmd定位到1:1方法,寻找其实现类进行执行。
时间: 2024-10-10 10:43:58