通过spring来配置某个命令号和执行方法之间的映射

整理的内容

1.手动获取spring的ApplicationContext和bean对象

写一个工具类实现ApplicationContextAware接口

2.反射的知识整理

3.前后端协议交互的时使用命令号,可以方便调用后端的执行方法

定义一个对象:ActionDefine,表示消息编号与消息处理类的映射定义

package com.youxigu.dynasty2.core.flex;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.youxigu.dynasty2.util.StringUtils;
import com.youxigu.wolf.net.codec.IAMF3Message;

/**
 * 消息编号与消息处理类的映射定义
 *
 * @author Administrator
 *
 */
public class ActionDefine {
    /**
     * 消息编号
     */
    private int cmd;

    /**
     * 消息处理类
     */
    private Object bean;
    /**
     * 消息处理类的处理方法
     */
    private String methodName;

    /**
     * 传入参数的类型
     */
    private Class<? extends IAMF3Message> inParmClass;

    /**
     * 返回参数的类型
     */
    private Class<? extends IAMF3Message> outParmClass;

    /**
     * 缓存Method实例,避免每次都查找Method
     */
    private transient Method method;
    private transient Method prevMethod;

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public Method getPrevMethod() {
        return prevMethod;
    }

    public void setPrevMethod(Method prevMethod) {
        this.prevMethod = prevMethod;
    }

    public int getCmd() {
        return cmd;
    }

    public void setCmd(int cmd) {
        this.cmd = cmd;
    }

    public Object getBean() {
        return bean;
    }

    public void setBean(Object bean) {
        this.bean = bean;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public Class<? extends IAMF3Message> getInParmClass() {
        return inParmClass;
    }

    public void setInParmClass(Class<? extends IAMF3Message> inParmClass) {
        this.inParmClass = inParmClass;
    }

    public Class<? extends IAMF3Message> getOutParmClass() {
        return outParmClass;
    }

    public void setOutParmClass(Class<? extends IAMF3Message> outParmClass) {
        this.outParmClass = outParmClass;
    }

}

spring配置文件中增加配置

<beans xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:aop="http://www.springframework.org/schema/aop"
         xmlns:tx="http://www.springframework.org/schema/tx"
         xmlns:flex="http://www.springframework.org/schema/flex"
         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
           http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
           http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
           http://www.springframework.org/schema/flex http://www.springframework.org/schema/flex/spring-flex-1.0.xsd">
    <!-- 11001命令代表要执行friendAction类中findUser方法-->
    <bean class="com.youxigu.dynasty2.core.flex.ActionDefine">
       <property name="cmd" value="11001"/>
       <property name="bean" ref="friendAction"/>
       <property name="methodName" value="findUser"/>
    </bean>

    <!-- 申请好友-11002-->
    <bean class="com.youxigu.dynasty2.core.flex.ActionDefine">
       <property name="cmd" value="11002"/>
       <property name="bean" ref="friendAction"/>
       <property name="methodName" value="appFriend"/>
    </bean>

     ...略

</beans>

手动初始化所有的actio定义,创建cmd和method的映射

实现类接口ApplicationContextAware 就要实现他的方法setApplicationContext(ApplicationContext ctx)

package com.youxigu.dynasty2.core.protobuf;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeoutException;

import org.apache.mina.core.session.IoSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.google.protobuf.Message;
import com.manu.core.ServiceLocator;
import com.youxigu.dynasty2.chat.EventMessage;
import com.youxigu.dynasty2.chat.MessageFilter;
import com.youxigu.dynasty2.chat.MessageFilter.FilterMessages;
import com.youxigu.dynasty2.chat.client.IChatClientService;
import com.youxigu.dynasty2.core.flex.ActionDefine;
import com.youxigu.dynasty2.core.flex.amf.AMF3WolfService;
import com.youxigu.dynasty2.core.flex.amf.IAMF3Action;
import com.youxigu.dynasty2.user.service.IAccountService;
import com.youxigu.dynasty2.util.BaseException;
import com.youxigu.wolf.net.IInitListener;
import com.youxigu.wolf.net.IWolfService;
import com.youxigu.wolf.net.OnlineUserSessionManager;
import com.youxigu.wolf.net.Response;
import com.youxigu.wolf.net.ResultMgr;
import com.youxigu.wolf.net.SocketContext;
import com.youxigu.wolf.net.SyncWolfTask;
import com.youxigu.wolf.net.UserSession;

/**
 * 接收并处理所有Flex客户端的请求
 *
 * @author Administrator
 *
 */
public class ProtobufWolfService implements IWolfService, IInitListener, ApplicationContextAware {

    public static Logger log = LoggerFactory.getLogger(AMF3WolfService.class);

    private Map<Integer, ActionDefine> actions = new HashMap<Integer, ActionDefine>();
    private List<ActionDefine> actionDefines;

    public void setActionDefines(List<ActionDefine> actionDefines) {
        this.actionDefines = actionDefines;
    }

    @Override
    public void setApplicationContext(ApplicationContext ctx) throws BeansException {
        if (actionDefines == null) {
            actionDefines = new ArrayList<ActionDefine>();

            while (ctx != null) {                //遍历所有的配置文件                //取出bean的类型为ActionDefine的所有bean
                Map<String, ActionDefine> maps = ctx.getBeansOfType(ActionDefine.class);
                if (maps.values() != null && maps.values().size() > 0) {
                    actionDefines.addAll(maps.values());
                }
                ctx = ctx.getParent();

            }
        }
        if (actionDefines != null) {
            // 初始化ActionDefine            //声明方法的传入值类型数组,后面会强制修改
            Class[] paramsType = { Object.class, Response.class };
            for (ActionDefine ad : actionDefines) {
                int cmd = ad.getCmd();//命令号
                if (actions.containsKey(cmd)) {
                    throw new BaseException("重复的命令号:" + cmd);
                }
                if (ad.getSubActionIds() == null) {try {                        //用方法名和传入值类型反射取到方法声明
                        Method m = ad.getBean().getClass().getDeclaredMethod(ad.getMethodName(), paramsType);
                        ad.setMethod(m);//有了method声明就可以invoke来调用方法了
                        String beforeMethodName = ad.getPrevMethodName();
                        if (beforeMethodName != null && !"".equals(beforeMethodName)) {
                            m = ad.getBean().getClass().getDeclaredMethod(beforeMethodName, paramsType);
                            ad.setPrevMethod(m);
                        }

                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                        log.error("action mapping is error : cmd={}", cmd);
                    }
                }
                actions.put(cmd, ad);
            }
            actionDefines.clear();
            actionDefines = null;
        }
    }

    public void init() {

    }

    @Override
    public Object handleMessage(Response response, Object message) {
        if (message instanceof com.google.protobuf.Message) {
            com.google.protobuf.Message params = (com.google.protobuf.Message) message;
            try {                //用名称反射取得字段声明
                Field cmdF = params.getClass().getDeclaredField("cmd_");
                if(cmdF != null) {
                    cmdF.setAccessible(true);                    //用Filed取得字段值
                    int cmd_ = cmdF.getInt(params);
                    //取得缓存中方法声明
                    ActionDefine ad = actions.get(cmd_);
                    Method m = null;

                    int cmd = ad.getCmd();
                    if (actions != null) {
                        ad = actions.get(cmd);
                        if (ad != null)
                            m = ad.getMethod();
                    }
                    if (m == null) {
                        throw new BaseException("错误的命令号:" + cmd);
                    }

                    //调用方法
                    Object retu_ = m.invoke(ad.getBean(), new Object[] { message, response });

//                    ........
                }

            } catch (Exception e) {
                e.printStackTrace();
            }

        }
        return null;
    }
}
时间: 2024-10-24 17:02:46

通过spring来配置某个命令号和执行方法之间的映射的相关文章

前端技术之:命令模块及其执行方法

一.创建一个命令模块1.package.json { "name": "@uad/nat-cli", "version": "0.0.2", "description": "Demo", "main": "index.js", "bin": { "artisan": "./src/artisan.j

spring获取类对象,类方法,执行方法

Object object = SpringConfigUtil.getBean(beanName);Method method = ReflectionUtils.findMethod(object.getClass(), methodName, PageVO.class);Map resultMap = (Map) ReflectionUtils.invokeMethod(method, object, pageVO); 原文地址:https://blog.51cto.com/butcher

记录一个 spring cloud 配置中心的坑,命令行端口参数无效,被覆盖

spring cloud 配置中心 结合GIT , 可以运行时更新配置文件.发送指令让应用重新读取配置文件. 最近在测试服务器实现了一套,结果CPU 实用率暴增,使用docker compose启动 restart always 多节点的服务一直重启关闭重启关闭. 日志文件记录了一个异常: 国内国外搜了一遍都没有解决 org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean wit

(二)Spring Boot配置

1.配置文件 Spring Boot使用一个全局的配置文件,额皮质文件名是固定的; application.properties application.yml 配置文件的作用:修改SpringBoot自动配置的默认值;SpringBoot在底层都给我们自动配置好; YAML(YAML Ain't Markup Language) YAML A Markup Language:是一个标记语言 YAML isn't Markup Language:不是一个标记语言; 标记语言: 以前的配置文件;大

Spring Boot 配置加载顺序详解

使用 Spring Boot 会涉及到各种各样的配置,如开发.测试.线上就至少 3 套配置信息了.Spring Boot 可以轻松的帮助我们使用相同的代码就能使开发.测试.线上环境使用不同的配置. 在 Spring Boot 里面,可以使用以下几种方式来加载配置.本章内容基于 Spring Boot 2.0 进行详解. 1.properties文件: 2.YAML文件: 3.系统环境变量: 4.命令行参数: 等等-- 我们可以在 Spring Beans 里面直接使用这些配置文件中加载的值,如:

Spring Boot 配置优先级顺序

http://www.cnblogs.com/softidea/p/5759180.html 一般在一个项目中,总是会有好多个环境.比如: 开发环境 -> 测试环境 -> 预发布环境 -> 生产环境 每个环境上的配置文件总是不一样的,甚至开发环境中每个开发者的环境可能也会有一点不同,配置读取可是一个让人有点伤脑筋的问题. Spring Boot提供了一种优先级配置读取的机制来帮助我们从这种困境中走出来. 常规情况下,我们都知道Spring Boot的配置会从application.pro

spring注解配置quartz

常规配置quartz可以参考我的另外一篇博文:http://www.cnblogs.com/yangzhilong/p/3349116.html spring配置文件里增加: 命令空间: http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd 配置: <task:annotation-driven/> 当然这还需要扫描注解等常规配置. ja

Linux网络属性配置相关命令

Linux网络属性配置相关命令: 前言: Linux属性配置可以分为两类.一类通过命令配置,另一类通过修改配置文件配置. Linux属性配置的相关命令可以分为三大类: 一.ifcfg命令家族:①ifconfig,②route,③netstat,④hostname ①ifconfig命令:主要负责接口及地址查看和管理 ifconfig [INTERFACE] #ifconfig -a:显示所有接口,包括inactive状态的接口.(包括激活和未激活的接口): 如图所示,-a选项将会显示所有接口,包

spring hibernate配置切换数据源,实现读写分离

spring的配置如下 <!-- 主数据源--> <bean id="masterDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <prope