您的位置:首页 > 编程语言 > Java开发

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

2016-03-24 21:21 633 查看

需求分析

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

接口服务与应用平台的通信标准化并实施通信加密。

应用无需考虑服务器硬件情况,仅需与接口服务通信即可完成所有功能对接。

接口服务前端接收应用平台请求数据,后端向服务器发送命令并接收结果。

接口服务的后端应根据功能需求指定规范,并要求厂商实现这些规范功能。

接口服务的后端应支持根据不同服务器类型灵活配置,实现模块化,并可以灵活配置和替换。

接口服务后端模块应与前端请求解耦,支持厂商自行开发后端实现模块。

接口服务在启动时应该实现对设备的认证,未通过认证的设备不允许对外提供服务。

程序设计

总体实际

我们计划将后端接口服务设计为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.0</modelVersion>
<groupId>org.wsy</groupId>
<artifactId>nmi</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>nmi</name>
<description>network management interface</description>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.wsy</groupId>
<artifactId>nmi-core</artifactId>
<type>jar</type>
<scope>compile</scope>
</dependency>
</dependencies>
</dependencyManagement>
<modules>
<module>nmi-core</module>
<module>nmi-front</module>
</modules>
</project>


nmi-front模块

<?xml version="1.0"?>
<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.0</modelVersion>
<parent>
<groupId>org.wsy</groupId>
<artifactId>nmi</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>nmi-front</artifactId>
<name>nmi-front</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.3.3.RELEASE</version>
</dependency>
<!-- nmi core -->
<!-- <dependency>
<groupId>com.rails</groupId>
<artifactId>nmi-core</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency> -->
<dependency>
<groupId>org.wsy</groupId>
<artifactId>nmi-core</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/nmi-core.jar</systemPath>
</dependency>
<!-- nmi core -->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>


nmi-core模块

<?xml version="1.0"?>
<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.0</modelVersion>
<parent>
<groupId>org.wsy</groupId>
<artifactId>nmi</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>nmi-core</artifactId>
<name>nmi-core</name>
<url>http://maven.apache.org</url>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<finalName>nmi-core</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</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中确实包含配置文件中的实现类,则顺利加载模块并执行认证过程。

启动、认证过程

以下为认证通过的启动过程截图:



可以看到模块顺利载入,并认证成功。

接口调用

模块加载成功同时认证成功后,可以正常调用接口。其中返回的”this is a A command service”即为假设A设备厂商的自定义服务返回的串。



模块存在但是认证失败

启动、认证过程

图上可以看出,已经顺利加载模块(XXDevice),但是设备认证失败了。



接口调用

可以看到接口是不能顺利调用的。



模块载入异常

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

启动、认证过程

可以看出,模块并未顺利加载(class not found err),因此无法认证设备。



接口调用

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

总结

Spring boot 实现REST风格的微服务

实现了接口微服务的前后分离解耦

通过反射机制按照配置动态加载接口实现

设计并实现了设备认证流程
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息