毕设项目,系统搭建笔记文档

代码结构:

 

主体系统启动流程:

在dynamic web project中添加全局监听类RootListener,继承ServletContextListener接口,实现public void contextInitialized(ServletContextEvent sce),调用系统初始化入口类ArchtechRoot。在ArchtechRoot中根据spring配置文件进行系统各模块的初始化。从root bean读取SystemInitDO,用于获取配置文件中的子配置文件,即各层模块配置文件,并将其中的bean进行装配。RPCServerRPC服务的基础server模块,对应rpcRoot bean。

 

1 ApplicationContext context = new ClassPathXmlApplicationContext("springContext-*.xml");
2 SystemInitDO initDO = (SystemInitDO) context.getBean("root");
3 RPCServer rpcRoot = (RPCServer) context.getBean("rpcRoot");

 

子配置文件:

 1 <bean id="root" class=" com.multiagent.hawklithm.davinci.init.SystemInitDO"> 
 2         <property name="configFileList">
 3             <list>
 4                 <value>spring-config/spring-asyntask.xml</value>
 5                 <value>spring-config/spring-EventListener.xml</value>
 6                 <value>spring-config/spring-dao.xml</value>
 7                 <value>spring-config/spring-manager.xml</value>
 8                 <value>spring-config/spring-module.xml</value>
 9                 <value>spring-config/spring-ibatis.xml</value>
10                 <value>spring-config/spring-net.xml</value>
11                 <value>spring-config/spring-transaction.xml</value>
12                 <value>spring-config/spring-session.xml</value>
13             </list>
14         </property>      
15     </bean>

子配置文件中几个关键注册管理机

bean 分类注册管理机

1 <!-- bean分类注册管理机 -->
2     <bean class="com.multiagent.hawklithm.davinci.init.AutoRegister"/>

异步任务注册机

1 <!-- 异步任务注册机 -->
2     <bean id="asynTaskRegManager" class="com.multiagent.hawklithm.davinci.AsynTaskRegisterMachine" />

消息注册管理机

1 <!-- 消息注册管理机 -->    
2     <bean id=" wardenManager" class="com.multiagent.hawklithm.shadowsong.manager.WardenManager"/>

生产过程模块管理机

1 <!-- 生产过程模块管理注册机 -->
2     <bean id="pmRegManager" class="com.multiagent.hawklithm.leon.manager.ProcessModuleRegisterManager"/>

 

bean注册管理机

 1 public class AutoRegister implements BeanPostProcessor {
 2     private AsynTaskRegisterMachine asynTaskRegManager;
 3     private ProxyFactoryBean accountService;
 4     private ProcessModuleRegisterManager pmRegManager;
27 public Object postProcessAfterInitialization(Object bean, String beanName) 28 throws BeansException { 29 if (bean instanceof AsynTaskRegister) { 30 System.out.println("bean name: "+beanName+" regist AsynTaskRegister"); 31 asynTaskRegManager.regist(bean);//异步任务注册 32 }else if (bean instanceof IProcessModule){ 33 System.out.println("bean name: "+beanName+" regist EquipmentObject"); 34 pmRegManager.regist(bean);//过程模块注册 35 } 36 return bean; 37 } 38 64 }

如代码所示,根据类类型就行分类注册

 

RPC接口注册:

RPC接口定义在springContext-rpc.xml中

如以下示例接口定义

1     <bean class="com.multiagent.hawklithm.davinci.rpc.DO.RPCSystemServerProxy">
2         <property name="interfaceName" value="com.multiagent.hawklithm.rpc.Interfacetest"/>
3         <property name="version" value="1.0.0.hawk"/>
4         <property name="className" value="com.multiagent.hawklithm.rpc.impl.ImplTest"/>
5         <property name="comment" value="此处填写接口介绍"/>
6         <property name="visible" value="true" />
7     </bean>

RPCServer创建

1 <bean id="rpcRoot" class="com.multiagent.hawklithm.davinci.rpc.Server.RPCServer">
2         <constructor-arg>
3             <value>10007</value>
4         </constructor-arg>
5 
6     </bean>

在RPCServer.java中,Rpc接口bean注册

1 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
2         if (bean instanceof RPCSystemServerProxy) {
3             RPCregManager.regist((RPCSystemServerProxy) bean);
4         }
5         return bean;
6     }

将已注册RPC接口与已注册模块关联:

ArchtechRoot.java

对已填充beanId字段的RPC接口类进行关联

 1 for (RPCSystemServerProxy object : rpcRoot.getRPCregManager().getRegList()) {
 2                 if (StringUtils.hasLength(object.getBeanId())) {
 3                     try {
 4                         Object target = tempContext.getBean(object.getBeanId());
 5                         object.setTarget(target);
 6                         System.out.println(object.getInterfaceName() + "关联成功");
 7                     } catch (NoSuchBeanDefinitionException e) {
 8                         // TODO 打印日志RPC配置文件中bean缺失
 9                         System.out.println("RPC配置文件中缺失bean:[" + object.getBeanId() + "]");
10                     }
11                 }
12             }

对未填充beanId字段的RPC接口类进行实例创建(目前均使用单例模式)

1 for (RPCSystemServerProxy object : rpcRoot.getRPCregManager().getRegList()) {
2                 if (!object.isLinked()) {
3                     object.setTarget(Class.forName(object.getClassName()).newInstance());
4                     System.out.println(object.getClassName() + "生成实例成功");
5                 }
6             }

以上完成所有模块的创建和注册关联工作

启动异步任务注册机中的所有异步任务:

1 regManager.startAll();

消息注册部分Shadowsong

消息注册管理机WardenManager.java

 1 public class WardenManager implements IRegisterManager, IMessagePusher<WardenMessage> {
 2     
 3     public boolean regist(Object object) {
 4     /**具体见源码*/
 5     }
 6 
 7     /**
 8      * Warden接收消息的异步线程
 9      * @author hawklithm
10      *
11      */
12     private class WardenThread implements Runnable {
13         /**具体见源码*/
14         @Override
15         public void run() {
16             object.receiveMessage(message);
17         }
18 
19     }
20 
21     /**
22      * 推送消息
23      */
24     public void push(WardenMessage message) {
25         Set<Warden> list = map.get(message.getKind());
26         for (Warden object : list) {
27             exec.execute(new WardenThread(object, message));
28         }
29     }
30 
31 }

使用消息注册机时先进行消息注册

1 wardenManager.registWarden(new Warden(“MessageReceiver”, “MessageType”) {
2 
3                         //message对应消息结构体WardenMessage中的note属性
4             @Override
5             public void asynchronizedProcess(String message) {
6                 /**接收到消息后的行为*/
7             }
8 
9         });

发送消息:

1 wardenManager.push(message);

message类型为WardenMessage

纯虚类EquipmentObjetc类型继承了WardenOperator接口实现方法

1 public void sendOutMessage(WardenMessage message) {
2         wardenManager.push(message);
3     }

所以继承了EquipmentObject的类直接调用sendOutMessage(WardenMessage message)即可。

举例:

读卡器模块初始化时(读卡器模块继承了EquipmentObject)

 1 this.registWarden(new Warden(String.valueOf(this.getRfid()) + WardenMessage.TARGET_TYPE_READER, WardenMessage.KIND_NEW_DATA_COMING + WardenMessage.DIR_ENTER) {
 2 
 3             @Override
 4             public void asynchronizedProcess(String message) {
 5                 WardenMessage wardenMessage = new WardenMessage();
 6                 wardenMessage.setNote(message);
 7                 wardenMessage.setTarget(String.valueOf(targetRFID) + targetKind);
 8                 wardenMessage.setKind(targetMessageKind + targetMessageDir);
 9                 sendOutMessage(wardenMessage);
10             }
11 
12         });

以上代码截取自Reader.java表示在接收到warden消息后将其信息实体取出并重新定义warden消息的目标和类型并转发,我们现在做一个约定:

消息接收者:目标RFID+目标类型

消息类型:消息类型+消息流向

WardenMessage.java中展示预设了几种消息类型

 1     /**
 2      * 消息类型
 3      */
 4     public static String KIND_RFID_FROM_READER = "wm_rfidfromreader";//从读卡器模块发送来的RFID数据
 5     public static String KIND_NEW_DATA_COMING = "new_data_coming";//接收到从RFID实体来的数据
 6     /**
 7      * 目标类型
 8      */
 9     public static String TARGET_TYPE_READER = "target_type_reader";//数据接收目标类型为读卡器
10     public static String TARGET_TYPE_MACHINE = "target_type_machine";//数据接收目标类型为设备模块
11     /**
12      * 数据流方向
13      */
14     public static String DIR_ENTER = "wm_enter";
15     public static String DIR_EXIT = "wm_exit";

模块间信息交互和数据传输均可使用该消息系统

生产过程管理模块(静态模块系统leon)

 1 public class ProcessModuleRegisterManager implements IRegisterManager {
 2     private List<IProcessModule> regList = new ArrayList<IProcessModule>();
 3     public boolean regist(Object thing) {
 4     /**过程模块注册*/
 5     }
 6 
 7     public IProcessModule getProcessModuleByName(String name) throws ProcessModuleNotFoundException {
 8 /**根据模块名称(ID)获取已注册的过程模块*/
 9     }
10 
11     public EquipmentObject getEquipmentByRFID(int id) throws ProcessModuleNotFoundException {
12         /**根据设备名称(ID)获取已注册的过程模块中的设备模块*/
13     }
14 }

过程注册模块中包含所有已注册的过程模块信息

生产过程模块(静态模块):

统一继承IProcessModule,具体见IProcessModule.java

 1 public interface IProcessModule {
 2     /**
 3      * 获取模块名称
 4      * @return 模块名称
 5      */
 6     String getName();
 7     /**
 8      * 根据设备RFID从过程模块中获取设备
 9      * @param id 设备RFID
10      * @return
11      * @throws EquipmentNotFoundException
12      */
13     EquipmentObject getEquipmentByRFID(int id) throws EquipmentNotFoundException;
14 }

在过程模块中建立设备列表,通过spring bean注入设备,可达到过程对设备的一个管理,实例见SortingProcess.java

对应bean的spring配置参考spring-module.xml,如下:

 1 <bean id="sorting_process_module" class="com.multiagent.hawklithm.leon.process.SortingProcess">
 2         <property name="equipmentList">
 3             <list>
 4                 <ref bean="reader1"/>
 5                 <ref bean="sorting_equipment1" />
 6                 <ref bean="reader2" />
 7                 <ref bean="singleRead3"/>
 8                 <ref bean="sorting_equipment2" />
 9                 
10             </list>
11         </property>
12     </bean>

设备模块

统一继承纯虚类EquipmentObject,在EquipmentObject.java中已实现设备的基本功能方法

 1 public abstract class EquipmentObject implements Module, WardenOperator {
 2     private int rfid ;
 3     private Set<Integer> itemRFIDs = new HashSet<Integer>();
 4     private Set<Integer> packageRFIDs = new HashSet<Integer>();
 5     private int staffRFID;
 6     private WardenManager wardenManager;
 7 
 8     
 9     /**
10      * 设置设备属性
11      */
12     abstract public void doSetEquipmentParameter();
13 
14     /**
15      * 获取设备属性
16      * @return
17      */
18     abstract public String doGetEquipmentSummaryInfo();
19 
20     /**
21      * 初始化Warden
22      */
23     abstract public void initWarden();
24 
25     public void sendOutMessage(WardenMessage message) {
26         wardenManager.push(message);
27     }
28 
29     public void registWarden(Warden warden) {
30         wardenManager.regist(warden);
31     }
32 
33     public void addItem(int RFID) {
34         itemRFIDs.add(Integer.valueOf(RFID));
35     }
36 
37     public void addPackage(int RFID) {
38         packageRFIDs.add(Integer.valueOf(RFID));
39     }
40 
41     public boolean removeItem(int RFID) {
42         return itemRFIDs.remove(Integer.valueOf(RFID));
43     }
44 
45     public boolean removePackage(int RFID) {
46         return packageRFIDs.remove(Integer.valueOf(RFID));
47     }
48 
49     // public EquipmentObject() {
50     // warden = new Warden(this);
51     // wardenManager.regist(warden);
52     // }
53 
54     public String doGetModuleSummaryInfo() {
55         return doGetEquipmentSummaryInfo();
56     }
57 
58     public int getStaffRFID() {
59         return staffRFID;
60     }
61 
62     public void setStaffRFID(int staffRFID) {
63         this.staffRFID = staffRFID;
64     }
65 
66     public WardenManager getWardenManager() {
67         return wardenManager;
68     }
69 
70     public void setWardenManager(WardenManager wardenManager) {
71         this.wardenManager = wardenManager;
72     }
98 }

在配置设备bean时注意设置init-method="initWarden"从而调用initWarden函数进行消息注册

例:

1 <bean id="sorting_equipment1"    class="com.multiagent.hawklithm.leon.module.SortingEquipmentModule"  init-method="initWarden" >
2         <property name="rfid" value="1024"/>
3     </bean>

initWarden中的注册warden见上文消息注册管理Shadowsong部分,具体实现见com.multiagent.hawklithm.leon.module包下的模块类

RPC系统

rpc client端在rpc工程中,server端在davinci中,rpc所有spring bean配置文件均在springContext-rpc.xml中,rpc接口信息通过interfaceInfoDAO保存到数据库中。

RPCServer.java

在initNetty()函数中创建Netty服务端实现通信

 1 private void initNetty() {
 2         ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
 3         bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
 4 
 5             @Override
 6             public ChannelPipeline getPipeline() throws Exception {
 7                 ChannelPipeline pipeline = Channels.pipeline();
 8                 pipeline.addLast("UP_FRAME_HANDLER", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2));
 9                 pipeline.addLast("DOWN_FRAME_HANDLER", new LengthFieldPrepender(2, false));
10                 pipeline.addLast("myHandler", rpcServerNettyHandler);
11                 // return Channels.pipeline(rpcServerNettyHandler);
12                 return pipeline;
13             }
14 
15         });
16         bootstrap.bind(new InetSocketAddress(port));
17         System.out.println("RPC server开启成功");
18     }

NettyHandler继承SimpleChannelHandler对通信接口进行一些基本封装

public class NettyHandler extends SimpleChannelHandler {

    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
            throws Exception {
/**接收到数据将通信相关数据取出并传入onMessageReceived方法*/
        ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
        String recvMsg=buffer.toString(Charset.defaultCharset());
        System.out.println("receive: " +recvMsg);
        onMessageReceived(recvMsg,e.getChannel());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
            throws Exception {
/**异常处理*/
    }

    public void sendMessage(String message,Channel channel) throws MessageTransportException {
        if (channel == null) {
            throw new MessageTransportException(new NullPointerException());
        }
        ChannelBuffer buffer = ChannelBuffers.buffer(message.length());
        buffer.writeBytes(message.getBytes());
        channel.write(buffer);
    }
    /**
     * 重写该函数可获取传输数据
     */
    public void onMessageReceived(String message,Channel channel) throws MessageTransportException {
        
    }
}

RPCServerNettyHandler继承NettyHandler

重写onMessageReceived

 1 @Override
 2     public void onMessageReceived(String msg, Channel cha) throws MessageTransportException {
 3         System.out.println(msg);
 4         RPCSystemProtocol rpcMessage = gson.fromJson(msg, RPCSystemProtocol.class);
 5         if (!aclManager.verifyRPCInterfaceCall(rpcMessage)) {//权限控制
 6             rpcMessage.setReturnObject("have no permission");
 7             return;
 8         }
 9         if (!rpcMessage.selfCheck()) {//数据自检
10             throw new MessageTransportException("RPC包错误");
11         }
12         try {
13             Object instance = RPCregManager.getTarget(rpcMessage);
14             Object ret = rpcExec.exec(rpcMessage.getClassName(), rpcMessage.getMethodName(), rpcMessage.getParamsType(), instance, rpcMessage.getParameters());//通过反射机制调用响应类的方法执行并得出结果
15             rpcMessage.setReturnObject(gson.toJson(ret));
16             if (!watcher.insert(new RPCConnectInfo(gson.toJson(rpcMessage), cha))) {//将需要返回的结果插入发送队列,由于开发RPC时还没有开始设计消息管理中心,所以使用其独立的RPCBufferCallBackWatcher类进行返回数据队列的管理,详见RPCBufferCallBackWatcher
17                 // TODO 打印日志
18             }
19         } catch (RPCInterfaceNotFoundException e) {
20             // TODO 打印日志
21             e.printStackTrace();
22             return;
23         } catch (IllegalAccessException e) {
24             // TODO Auto-generated catch block
25             e.printStackTrace();
26             return;
27         } catch (IllegalArgumentException e) {
28             // TODO Auto-generated catch block
29             e.printStackTrace();
30             return;
31         } catch (InvocationTargetException e) {
32             // TODO Auto-generated catch block
33             e.printStackTrace();
34             return;
35         }
36     }

rpc client端

客户端进行RPC调用思路:

在配置文件中注册需要使用rpc的bean,通过该bean获取一个实例并使用对应的接口方法,利用spring的特性对该接口方法进行代理,将方法的实现转换成netty通信,把调用方法的参数发送给rpc server,并在rpcLockManager中进行一个注册并阻塞当前方法执行线程,等待server返回结果;当server返回结果后,在rpcLockManager中对等待结果的调用进行解锁并唤醒线程,传入server发过来的结果,再又代理返回方法调用结果。使客户端程序员的编码结构不发生任何改变的情况下实现远程调用。

RPCClient.java

基本上和RCPServer.java类似,不过这里创建的是netty服务端

 1 public void initRPCClient() {
 2         ClientBootstrap bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
 3         handler = new NettyHandler() {
 4 
 5             private Gson gson = new Gson();
 6 
 7             @Override
 8             public void onMessageReceived(String msg, Channel cha) throws MessageTransportException {
 9                 RPCSystemProtocol rpcMessage = gson.fromJson(msg, RPCSystemProtocol.class);
10                 if (!rpcMessage.selfCheck()) {
11                     throw new MessageTransportException("RPC包错误");
12                 }
13                 // announcer.insert(rpcMessage);
14                 lockManager.AnswerReceived(rpcMessage.uuid, rpcMessage);//接收到服务端回复后将结果返回并将rpc调用解锁
15 
16             }
17 
18             @Override
19             public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
20                 channel = e.getChannel();
21             }
22         };
23         bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
24             public ChannelPipeline getPipeline() throws Exception {
25                 ChannelPipeline pipeline = Channels.pipeline();
26                 pipeline.addLast("UP_FRAME_HANDLER", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2));
27                 pipeline.addLast("DOWN_FRAME_HANDLER", new LengthFieldPrepender(2, false));
28                 // return Channels.pipeline(handler);
29                 pipeline.addLast("myHandler", handler);
30                 return pipeline;
31             }
32         });
33         bootstrap.connect(new InetSocketAddress(address, port));
34     }

 

用SpringMethodInterceptor对rpc调用类的实现进行代理

 1 public class SpringMethodInterceptor implements MethodInterceptor {
 2 
 3 
 4     public Object invoke(MethodInvocation inv) throws Throwable {
 5     System.out.println(inv.getMethod().getDeclaringClass().getName() + " " + inv.getArguments());
 6         String version=rpcProxyRegManager.getVersion(inv.getMethod().getDeclaringClass().getName());
 7         RPCSystemProtocol message=RPCSystemProtocolPackageUtil.getRPCProtocolPackage(inv.getMethod(),inv.getArguments(),version);
 8         rpcClient.sendRPCProtocol(message);//发送调用协议
 9         UUID uuidOrigin=message.uuid;
10         RPCSystemProtocol recvMessage=lockManager.waitforAnswer(uuidOrigin);//阻塞当前线程,等待rpcServer返回调用结果
11         Class<?> returnType=inv.getMethod().getReturnType();
12         return gson.fromJson(recvMessage.getReturnObject(),returnType);
13 
14     }
15 
16 }

 

读卡器部分:

采用netty接收读卡器数据

 1 public void initReaderServer() {
 2         ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
 3         bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
 4 
 5             @Override
 6             public ChannelPipeline getPipeline() throws Exception {
 7                 ChannelPipeline pipeline = Channels.pipeline();
 8                 pipeline.addLast("UP_FRAME_HANDLER", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 2, 0, 2));
 9                 pipeline.addLast("DOWN_FRAME_HANDLER", new LengthFieldPrepender(2, false));
10                 pipeline.addLast("myHandler", readerNettyHandler);
11                 // return Channels.pipeline(rpcServerNettyHandler);
12                 return pipeline;
13             }
14 
15         });
16         bootstrap.bind(new InetSocketAddress(port));
17         System.out.println("reader data server开启成功");
18     }

接收到读卡器数据后的操作如下,详见ReaderDataManager.java

1     public void OriginalDataDealing(RFIDOriginalInfos infos){
2         submitData(infos.getInfos());//存入数据库
3         sendOutDataComingMessage(infos);//发送消息给读卡器模块进行状态定义
4     }

通过消息中心将接收到的读卡器数据推送给读卡器模块

 1     private void sendOutDataComingMessage(RFIDOriginalInfos infos){
 2         WardenMessage msg=new WardenMessage();
 3         msg.setKind(WardenMessage.KIND_NEW_DATA_COMING+WardenMessage.DIR_ENTER);
 4         String target="";
 5         for (String s:infos.getTargets()){
 6             target+=s+WardenMessage.TARGET_TYPE_READER+"|";
 7         }
 8         msg.setTarget(target);
 9         
10         msg.setNote(gson.toJson(infos.getInfos()));
11         readerMessageComingPusher.sendOutMessage(msg);
12     }

由上文设备模块的创建方法可创建读卡器设备模块,详情见Reader.java

 1 public class Reader extends EquipmentObject {
 2 
 3     private int targetRFID = 0;
 4     private String targetMessageKind = "";
 5     private String targetKind = "";
 6     private String targetMessageDir = "";
 7 
 8     @Override
 9     public void initWarden() {
10     
11         this.registWarden(new Warden(String.valueOf(this.getRfid()) + WardenMessage.TARGET_TYPE_READER, WardenMessage.KIND_NEW_DATA_COMING + WardenMessage.DIR_ENTER) {
12 
13             @Override
14             public void asynchronizedProcess(String message) {
15                 WardenMessage wardenMessage = new WardenMessage();
16                 wardenMessage.setNote(message);
17                 wardenMessage.setTarget(String.valueOf(targetRFID) + targetKind);
18                 wardenMessage.setKind(targetMessageKind + targetMessageDir);
19                 sendOutMessage(wardenMessage);
20             }
21 
22         });
23     }
24 
25 }

在reader模块中注册了对读卡器新接收到数据的信息的监听

 

 

posted @ 2013-12-06 15:05  瀑布飞鹰  阅读(624)  评论(0编辑  收藏  举报