基于SpringBoot的通用设备操作接口服务

需求分析

我们有一个应用平台需要和某特殊服务器对接,实现对特殊服务器的一些操作以及状态信息的读取。但是该服务器由多个厂商完成,且每个厂商的实现方式不同,因此不能通过应用平台逐一实现每个厂商的接口调用。我们考虑在特殊服务器端部署一个通用操作接口服务,应用平台仅仅与该接口通信,而具体的命令下发则由该通用操作接口服务实施。此时,仅需在接口服务项目中实现不同厂商的命令实现即可。该接口服务的需求如下:

  • 接口服务与应用平台的通信标准化并实施通信加密。
  • 应用无需考虑服务器硬件情况,仅需与接口服务通信即可完成所有功能对接。
  • 接口服务前端接收应用平台请求数据,后端向服务器发送命令并接收结果。
  • 接口服务的后端应根据功能需求指定规范,并要求厂商实现这些规范功能。
  • 接口服务的后端应支持根据不同服务器类型灵活配置,实现模块化,并可以灵活配置和替换。
  • 接口服务后端模块应与前端请求解耦,支持厂商自行开发后端实现模块。
  • 接口服务在启动时应该实现对设备的认证,未通过认证的设备不允许对外提供服务。

程序设计

总体实际

我们计划将后端接口服务设计为REST风格的微服务,因此采用Spring boot作为框架基础。同时考虑到前后解耦的需求,我们将项目拆分为前后端两个模块。如下所示:
nmi为项目名:network management interface

--> nmi (父项目)
|-->nmi-front(前端模块)
|-->nmi-core(后端模块)

如上所示,整体项目由MAVEN管理,将项目拆分后,nmi-core以jar包形式引入nmi-front中。我们在nmi-core中制定好接口interface,不同厂商的则可以在该模块模板的基础上开发各自对应的nmi-core.jar。这样在最终部署时即可通过替换nmi-core.jar实现对不同设备的定制。

MAVEN构建

nmi父项目

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <groupId>org.wsygroupId>
    <artifactId>nmiartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <packaging>pompackaging>
    <name>nminame>
    <description>network management interfacedescription>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.wsygroupId>
                <artifactId>nmi-coreartifactId>
                <type>jartype>
                <scope>compilescope>
            dependency>
        dependencies>
    dependencyManagement>
    <modules>
        <module>nmi-coremodule>
        <module>nmi-frontmodule>
    modules>
project>

nmi-front模块


<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0modelVersion>
  <parent>
    <groupId>org.wsygroupId>
    <artifactId>nmiartifactId>
    <version>0.0.1-SNAPSHOTversion>
  parent>
  <artifactId>nmi-frontartifactId>
  <name>nmi-frontname>
  <url>http://maven.apache.orgurl>
  <properties>
    <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
  properties>
  <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
            <version>1.3.3.RELEASEversion>
        dependency>
        
        
        <dependency>
            <groupId>org.wsygroupId>
            <artifactId>nmi-coreartifactId>
            <version>0.0.1-SNAPSHOTversion>
            <scope>systemscope>
            <systemPath>${project.basedir}/lib/nmi-core.jarsystemPath>
        dependency>   
        
    dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-maven-pluginartifactId>
            plugin>
        plugins>
    build>
project>

nmi-core模块


<project
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
    xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <modelVersion>4.0.0modelVersion>
    <parent>
        <groupId>org.wsygroupId>
        <artifactId>nmiartifactId>
        <version>0.0.1-SNAPSHOTversion>
    parent>
    <artifactId>nmi-coreartifactId>
    <name>nmi-corename>
    <url>http://maven.apache.orgurl>
    <packaging>jarpackaging>
    <properties>
        <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    properties>
    <build>
        <finalName>nmi-corefinalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-compiler-pluginartifactId>
            plugin>
        plugins>
    build>

project>

代码设计

模块结构

core

core仅需负责硬件命令的下发和设备认证,如有需要添加日志功能。因此包结构如下:
|>org.wsy.nmi.core
|--|>org.wsy.nmi.core.command
|--|--|>ICommand.java
|--|--|>ACommand.java
|--|>org.wsy.nmi.core.device
|--|--|>IDevice.java
|--|--|>ADevice.java
|--|>org.wsy.nmi.core.log
|--|--|>logger.java

其中ICommand.java 接口定义了所有设备应该实现的操作。IDevice.java 接口定义了设备认证相关的操作。

ACommand.java 以及 ADevice.java 为某厂商(如:A)的具体接口实现。

front

项目结构

nmi-front 模块带有主要的Spring boot特性,有Application启动器,controller等模块。结构如下

|>org.wsy.nmi.front
|--|>org.wsy.nmi.front.controllers
|--|--|>RequestController.java
|--|>org.wsy.nmi.front.module
|--|--|>org.wsy.nmi.front.module.config
|--|--|--|>Config.java
|--|--|>org.wsy.nmi.front.module.factory
|--|--|--|>CommandServiceFactory.java
|--|--|--|>DeviceAuthFactory.java
|--|--|>org.wsy.nmi.front.module.task
|--|--|--|>InitTask.java
|--|--|>org.wsy.nmi.front.module.cache
|--|--|--|>GlobalCache.java
|--|>Application.java

主要代码说明

Application.java(sping boot 启动器)
@SpringBootApplication
//需要支持外部配置properties文件
@EnableConfigurationProperties({ DeviceConfig.class })
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }
}
Config.java(配置映射)
//读取指定项目
@ConfigurationProperties(prefix="device")
public class DeviceConfig {
    private String mac;
    private String infname;
    private String deviceauth;
    private String commandservice;
    //....以下省略
InitTask.java(项目启动后的动作)

附:其中的GlobalCache,DeviceAuthFactory,CommandServiceFactory的具体实现在后边标出。

//这部分代码主要负责项目启动完毕后的设备认证等工作
@Component
public class PostTask {
    DeviceAuth auth = null;
    @Autowired
    DeviceConfig config;
    @PostConstruct
    public void init() {
        System.out.println("init finished");
        try {
            //从properties文件读取具体实现的Class路径,在后边通过反射加载
            String deviceAuthClass = config.getDeviceauth();
            String commandService = config.getCommandservice();
            //根据配置加载模块
            System.out.println("\n********  registering module  ********");

            try {
                //加载设备认证模块
                auth = DeviceAuthFactory.getInstance().build(deviceAuthClass).getAuth();
                GlobalCache.getInstance().setDeviceAuthState(auth.deviceAuth());

                if (GlobalCache.getInstance().isDeviceAuthState()) {
                    //如果认证通过则继续加载命令执行模块
                    System.out.println("device auth success!");
                    System.out.println("loading command service ...");
                    GlobalCache.getInstance().setCommandService(
                            CommandServiceFactory.getInstance().build(commandService).getCommandService());
                } else {
                    //如果认证过程失败则标记为认证失败
                    GlobalCache.getInstance().setDeviceAuthState(false);
                    System.out.println("device auth fail!");
                }

            } catch (Exception e) {
                //如果设备认证模块加载失败则标记为认证失败
                System.out.println("init fail, error:"+e);
                GlobalCache.getInstance().setDeviceAuthState(false);
            }

        } catch (Exception e) {
            System.out.println("auth err");
        }
    }

}
CommandServiceFactory(命令实现加载器)

通过单例模式实现,仅需一次加载即可,DeviceAuthFactory的加载机制相同,这里就不赘述了。

public class CommandServiceFactory {
    private volatile static CommandServiceFactory  instance;
    private String className;
    private CommandService service;
        public static CommandServiceFactory getInstance(){
        if (instance== null) {
            synchronized(CommandServiceFactory.class){
                if(instance == null){
                    instance = new CommandServiceFactory();
                }
            }
        }
        return instance;
    }
    private CommandServiceFactory(){ }
    //通过反射动态加载
    public CommandServiceFactory build(String className) throws Exception{
        this.className = className;
        service = (CommandService) Class.forName(className).newInstance();
        return this;
    }
    public CommandService getCommandService() {
        return service;
    }
    public String getClassName(){
        return className;
    }
}
GlobalCache.java(全局变量)

同样以单例形式实现,用于存储认证结果,设备信息等。
具体实现略。

程序效果

配置截图

以下均是假设配置
这里写图片描述

运行效果

模块存在并设备认证成功

假设nmi-core.jar中确实包含配置文件中的实现类,则顺利加载模块并执行认证过程。

启动、认证过程

以下为认证通过的启动过程截图:
基于SpringBoot的通用设备操作接口服务_第1张图片
可以看到模块顺利载入,并认证成功。

接口调用

模块加载成功同时认证成功后,可以正常调用接口。其中返回的”this is a A command service”即为假设A设备厂商的自定义服务返回的串。
基于SpringBoot的通用设备操作接口服务_第2张图片

模块存在但是认证失败

启动、认证过程

图上可以看出,已经顺利加载模块(XXDevice),但是设备认证失败了。
基于SpringBoot的通用设备操作接口服务_第3张图片

接口调用

可以看到接口是不能顺利调用的。
基于SpringBoot的通用设备操作接口服务_第4张图片

模块载入异常

比如配置文件错误,厂商并未实现接口,则无法顺利载入模块,也会造成认证失败。

启动、认证过程

可以看出,模块并未顺利加载(class not found err),因此无法认证设备。
基于SpringBoot的通用设备操作接口服务_第5张图片

接口调用

和上文的认证失败是相同的,因此不在列举。

总结

  • Spring boot 实现REST风格的微服务
  • 实现了接口微服务的前后分离解耦
  • 通过反射机制按照配置动态加载接口实现
  • 设计并实现了设备认证流程

你可能感兴趣的:(Web后端开发)