0%

SpringBoot中异步调用的使用

同步请求是会一直等待服务端相应的,需要返回结果给客户端的;而异步调用服务端会马上返回给客户端响应,完成这次整个的请求,至于异步调用的任务服务端后台自己慢慢跑就行,客户端不会关心。

  1. 开启异步调用,在启动类增加@EnableAsync使异步调用@Async注解生效
@EnableAsync
public class DbCompareApplication {
    public static void main(String[] args) {
        SpringApplication.run(DbCompareApplication.class, args);
    }
}
  1. 在需要异步调用的方法,增加注解@Async
@Component
public class TestSleep {
    @Async
    public void sleep(){
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("sleep");;
    }
}
  1. Controller调用异步方法
@RestController
public class TaskController {
    @Autowired
    TestSleep testSleep;
    @GetMapping("/test")
    public String test(){
        testSleep.sleep();
        return "ok";
    }
}
  1. 效果
  • 如果不加@Async注解,客户端的调用,需要10秒才能返回结果;
  • 加了@Async注解,客户端的调用立马返回结果,调用的方法在服务端后台运行.
  1. 注意事项:部分情况下@Async注解失效
  • 调用同一个类下注有@Async异步方法
  • 调用的是静态(static)方法
  • 调用(private)私有化方法

下载

配置ssh无密码登录

# 测试ssh localhost, 默认需要密码
[root@node1 hadoop]# ssh localhost
The authenticity of host 'localhost (::1)' can't be established.
ECDSA key fingerprint is SHA256:Ii9RadytomW4X2LEvMQwRxoOTeGgxfNbOgwXrc/wwZI.
ECDSA key fingerprint is MD5:bc:b5:ef:93:e6:fd:7c:cd:a3:4f:a7:f6:4c:24:c7:a7.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'localhost' (ECDSA) to the list of known hosts.
root@localhost's password: 
ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
# 测试免密登录,无需密码即可登录成功
[root@node1 hadoop]# ssh localhost
Last failed login: Thu May  7 11:44:07 CST 2020 from localhost on ssh:notty
There was 1 failed login attempt since the last successful login.
Last login: Thu May  7 11:43:04 2020 from 192.168.41.1
[root@node1 ~]# 

配置java环境

#已经部署过了
[root@node1 hadoop]# echo $JAVA_HOME
/usr/local/bin/jdk1.8.0_112

安装hadoop

hadoop-2.7.7.tar.gz拷贝到/root/hadoop目录下并解压.

[root@node1 hadoop]# pwd
/root/hadoop
[root@node1 hadoop]# tar -zxvf hadoop-2.7.7.tar.gz 

/etc/profile或者~/.bash_profile配置环境变量HADOOP_HOME.

export HADOOP_HOME=/root/hadoop/hadoop-2.7.7
export PATH=$PATH:$HADOOP_HOME/bin

使配置生效

source /etc/profile

配置hadoop

进入$HADOOP_HOME/etc/hadoop目录,配置hadoop-env.sh等。涉及的配置文件如下:

hadoop-2.9.2/etc/hadoop/hadoop-env.sh
hadoop-2.9.2/etc/hadoop/yarn-env.sh
hadoop-2.9.2/etc/hadoop/core-site.xml
hadoop-2.9.2/etc/hadoop/hdfs-site.xml
hadoop-2.9.2/etc/hadoop/mapred-site.xml
hadoop-2.9.2/etc/hadoop/yarn-site.xml
  1. 配置hadoop-env.sh
# The java implementation to use.
export JAVA_HOME=${JAVA_HOME}
  1. 配置yarn-env.sh
#export JAVA_HOME=/home/y/libexec/jdk1.6.0/
  1. 配置core-site.xml
<configuration>
<property>
  <name>fs.default.name</name>
  <value>hdfs://192.168.41.128:9000</value>
  <description>HDFS的URI,文件系统://namenode标识:端口号</description>
</property>

<property>
  <name>hadoop.tmp.dir</name>
  <value>/root/hadoop/tmp</value>
  <description>namenode上本地的hadoop临时文件夹</description>
</property>
</configuration>
  1. 配置hdfs-site.xml
<configuration>
<property>
  <name>dfs.name.dir</name>
  <value>/root/hadoop/name</value>
  <description>namenode上存储hdfs名字空间元数据 </description> 
</property>

<property>
  <name>dfs.data.dir</name>
  <value>/root/hadoop/data</value>
  <description>datanode上数据块的物理存储位置</description>
</property>

<property>
  <name>dfs.replication</name>
  <value>1</value>
  <description>副本个数,配置默认是3,应小于datanode机器数量</description>
  </property>
</configuration>
  1. 配置mapred-site.xml
<configuration>
<property>
  <name>mapreduce.framework.name</name>
  <value>yarn</value>
  </property>
</configuration>
  1. 配置yarn-site.xml
<configuration>
<property>
  <name>yarn.nodemanager.aux-services</name>
  <value>mapreduce_shuffle</value>
</property>
<property>
  <name>yarn.resourcemanager.webapp.address</name>
  <value>${yarn.resourcemanager.hostname}:8099</value>
</property>
</configuration>

启动hadoop

  1. 格式化hdfs文件系统
bin/hadoop namenode -format
  1. 启动namenode
sbin/hadoop-daemon.sh start namenode
  1. 启动datanode
sbin/hadoop-daemon.sh start datanode
  1. 启动yarn
sbin/start-yarn.sh
  1. 验证
    查看logs/目录下是否有错误日志,通过jps命令查看后台进程.
[root@node1 hadoop-2.7.7]# jps
17152 NodeManager
17920 Jps
16721 DataNode #数据节点
16866 ResourceManager
62190 HMaster # Hbase
16623 NameNode #名称节点
  1. 查看UI

提交MapReduce作业

bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar pi 2 100

hdfs使用

  1. 创建一个目录
hadoop fs -mkdir /test
  1. 上传一个文件到指定目录
hadoop fs -put README.txt /test

或者

hadoop fs -moveFromLocal README.txt /test
  1. 查看目录下文件
[root@node1 hadoop-2.7.7]# hadoop fs -ls /test

更多命令参考

Hadoop版本支持矩阵:

  • S=支持
  • X=不支持
  • NT=未测试
HBase的-1.1.x中 HBase的-1.2.x的 HBase的-1.3.x的 HBase的-2.0.x版本
Hadoop-2.0.x-alpha X X X X
Hadoop-2.1.0-beta X X X X
Hadoop-2.2.0 NT X X X
Hadoop-2.3.x NT X X X
Hadoop-2.4.x S S S X
Hadoop-2.5.x S S S X
Hadoop-2.6.0 X X X X
Hadoop-2.6.1+ NT S S S
Hadoop-2.7.0 X X X X
Hadoop-2.7.1+ NT S S S
Hadoop-2.8.0 X X X X
Hadoop-2.8.1 X X X X
Hadoop-3.0.0 NT NT NT NT

建议使用 Hadoop 2.x:Hadoop 2.x 速度更快,包括短路读取功能,这将有助于提高您的 HBase 随机读取配置文件;Hadoop 2.x 还包括重要的 bug 修复,可以改善您的整体 HBase 体验;HBase 不支持使用早期版本的 Hadoop 运行;有关特定于不同 HBase 版本的要求,请参见下表;Hadoop 3.x 仍处于早期访问版本中,尚未被 HBase 社区对生产用例进行充分测试。

命令 使用方法 说明
ls hadoop fs -ls 返回文件详细信息或者目录列表
lsr hadoop fs -lsr 递归返回文件详细信息或者目录列表,类似ls -R
cat hadoop fs -cat URI 返回文件内容
chgrp hadoop fs -chgrp [-R] GROUP URI 改变文件所属组
chmod hadoop fs -chmod [-R] 改变文件的权限
chown hadoop fs -chown [-R] 改变文件拥有者
put hadoop fs -put 上传文件
copyFromLocal hadoop fs -copyFromLocal URI 上传文件
moveFromLocal hadoop fs -moveFromLocal 上传文件
get hadoop fs -get [-ignorecrc] [-crc] 下载文件
copyToLocal hadoop fs -copyToLocal [-ignorecrc] [-crc] 下载文件
cp hadoop fs -cp URI 复制文件
du hadoop fs -du URI 显示所有文件大小
dus hadoop fs -dus 显示文件大小
expunge hadoop fs -expunge 清空回收站
getmerge hadoop fs -getmerge [addnl]
mkdir hadoop fs -mkdir 创建目录
mv hadoop fs -mv URI 移动
rm hadoop fs -rm URI 删除非空目录和文件
rmr hadoop fs -rmr 递归删除
setrep hadoop fs -setrep [-R] 改变文件副本数
stat hadoop fs -stat URI 返回统计信息
tail hadoop fs -tail [-f] URI 返回文件尾部1K字节内容
test hadoop fs -test -[ezd] URI -e检查文件是否存在,-z检查文件是否为空,-d检查文件是否是目录
text hadoop fs -text 将文件输出和为文本格式,允许的格式zip TextRecordInputStream
touchz hadoop fs -touchz 创建一个空文件

问题

import java.sql.Timestamp;
//对象中属性为
private Timestamp startTime;
private Timestamp endTime;

通过spring boot restful接口返回到前端,时区自动转换不对,晚八个小时:

{
    "id": 0,
    "startTime": "2020-04-29T06:15:00.000+0000",
    "endTime": "2020-04-29T06:15:00.000+0000",
    "taskResult": false
}

解决办法

application.yml中指定日期格式和时区

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: Asia/Shanghai

再次测试:

{
    "id": 0,
    "startTime": "2020-04-29 14:15:00",
    "endTime": "2020-04-29 14:15:00",
    "taskResult": false
}

创建一个spring boot web基本项目

引入dataway相关依赖

<!-- hasor-spring 负责 Spring 和 Hasor 框架之间的整合。 -->
<dependency>
    <groupId>net.hasor</groupId>
    <artifactId>hasor-spring</artifactId>
    <version>4.1.3</version>
</dependency>
<!-- hasor-dataway 是工作在 Hasor 之上,利用 hasor-spring 我们就可以使用 dataway了。 -->
<dependency>
    <groupId>net.hasor</groupId>
    <artifactId>hasor-dataway</artifactId>
    <version>4.1.3-fix20200414</version><!-- 4.1.3 包存在UI资源缺失问题 -->
</dependency>
<!-- 数据库相关依赖 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.30</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.21</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>

mysql数据库中创建表

CREATE TABLE `interface_info` (
    `api_id`          int(11)      NOT NULL AUTO_INCREMENT   COMMENT 'ID',
    `api_method`      varchar(12)  NOT NULL                  COMMENT 'HttpMethod:GET、PUT、POST',
    `api_path`        varchar(512) NOT NULL                  COMMENT '拦截路径',
    `api_status`      int(2)       NOT NULL                  COMMENT '状态:0草稿,1发布,2有变更,3禁用',
    `api_comment`     varchar(255)     NULL                  COMMENT '注释',
    `api_type`        varchar(24)  NOT NULL                  COMMENT '脚本类型:SQL、DataQL',
    `api_script`      mediumtext   NOT NULL                  COMMENT '查询脚本:xxxxxxx',
    `api_schema`      mediumtext       NULL                  COMMENT '接口的请求/响应数据结构',
    `api_sample`      mediumtext       NULL                  COMMENT '请求/响应/请求头样本数据',
    `api_create_time` datetime     DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
    `api_gmt_time`    datetime     DEFAULT CURRENT_TIMESTAMP COMMENT '修改时间',
    PRIMARY KEY (`api_id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COMMENT='Dataway 中的API';

CREATE TABLE `interface_release` (
    `pub_id`          int(11)      NOT NULL AUTO_INCREMENT   COMMENT 'Publish ID',
    `pub_api_id`      int(11)      NOT NULL                  COMMENT '所属API ID',
    `pub_method`      varchar(12)  NOT NULL                  COMMENT 'HttpMethod:GET、PUT、POST',
    `pub_path`        varchar(512) NOT NULL                  COMMENT '拦截路径',
    `pub_status`      int(2)       NOT NULL                  COMMENT '状态:0有效,1无效(可能被下线)',
    `pub_type`        varchar(24)  NOT NULL                  COMMENT '脚本类型:SQL、DataQL',
    `pub_script`      mediumtext   NOT NULL                  COMMENT '查询脚本:xxxxxxx',
    `pub_script_ori`  mediumtext   NOT NULL                  COMMENT '原始查询脚本,仅当类型为SQL时不同',
    `pub_schema`      mediumtext       NULL                  COMMENT '接口的请求/响应数据结构',
    `pub_sample`      mediumtext       NULL                  COMMENT '请求/响应/请求头样本数据',
    `pub_release_time`datetime     DEFAULT CURRENT_TIMESTAMP COMMENT '发布时间(下线不更新)',
    PRIMARY KEY (`pub_id`)
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8mb4 COMMENT='Dataway API 发布历史。';

create index idx_interface_release on interface_release (pub_api_id);

application.properties中配置hasor-dataway和数据源

# 是否启用 Dataway 功能(必选:默认false)
HASOR_DATAQL_DATAWAY=true
# 是否开启 Dataway 后台管理界面(必选:默认false)
HASOR_DATAQL_DATAWAY_ADMIN=true
# dataway  API工作路径(可选,默认:/api/)
HASOR_DATAQL_DATAWAY_API_URL=/api/
# dataway-ui 的工作路径(可选,默认:/interface-ui/)
HASOR_DATAQL_DATAWAY_UI_URL=/ui/
# SQL执行器方言设置(可选,建议设置)
HASOR_DATAQL_FX_PAGE_DIALECT=mysql

# db
spring.datasource.url=jdbc:mysql://192.168.41.128:3306/compare?useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type:com.alibaba.druid.pool.DruidDataSource
# druid
spring.datasource.druid.initial-size=3
spring.datasource.druid.min-idle=3
spring.datasource.druid.max-active=10
spring.datasource.druid.max-wait=60000
spring.datasource.druid.stat-view-servlet.login-username=admin
spring.datasource.druid.stat-view-servlet.login-password=admin
spring.datasource.druid.filter.stat.log-slow-sql=true
spring.datasource.druid.filter.stat.slow-sql-millis=1

把数据源设置到 Hasor 容器中

首先新建一个 Hasor 的 模块,并且将其交给 Spring 管理。然后把数据源通过 Spring 注入进来。

@DimModule
@Component
public class ExampleModule  implements SpringModule {
    @Autowired
    private DataSource dataSource = null;

    @Override
    public void loadModule(ApiBinder apiBinder) throws Throwable {
        // .DataSource form Spring boot into Hasor
        apiBinder.installModule(new JdbcModule(Level.Full, this.dataSource));
    }
}

Hasor 启动的时候会调用 loadModule 方法,在这里再把 DataSource 设置到 Hasor 中。

在SprintBoot 中启用 Hasor

@EnableHasor()
@EnableHasorWeb()
@SpringBootApplication(scanBasePackages = { "com.deri.dataway.component" })
public class DatawayApplication {
    public static void main(String[] args) {
        SpringApplication.run(DatawayApplication.class, args);
    }
}

启动应用

相关日志

 _    _                        ____              _
| |  | |                      |  _ \            | |
| |__| | __ _ ___  ___  _ __  | |_) | ___   ___ | |_
|  __  |/ _` / __|/ _ \| '__| |  _ < / _ \ / _ \| __|
| |  | | (_| \__ \ (_) | |    | |_) | (_) | (_) | |_
|_|  |_|\__,_|___/\___/|_|    |____/ \___/ \___/ \__|
2020-04-29 09:29:11.899  INFO 43336 --- [           main] net.hasor.dataway.config.DatawayModule   : dataway api workAt /api/
2020-04-29 09:29:11.899  INFO 43336 --- [           main] n.h.c.environment.AbstractEnvironment    : var -> HASOR_DATAQL_DATAWAY_API_URL = /api/.
2020-04-29 09:29:11.903  INFO 43336 --- [           main] net.hasor.dataway.config.DatawayModule   : dataway admin workAt /ui/

访问接口管理页面进行在线接口开发

  • http://localhost:8080/ui/

    注意:地址最后的/不能不写.

DataQL

新建一个restful接口,其中var query = @@sql()<% ... %>是用来定义SQL外部代码块,并将这个定义存入 query变量名中。<% %> 中间的就是SQL语句。

var query = @@sql()<%
    select * from interface_info
%>
return query()

运行测试没有问题,就可以保存-发布了.

方便测试,请求方式可以写GET/api/后面写上接口的路径.如/api/test

发布成功后,就可以访问刚刚发布的接口了
http://localhost:8080/api/test.

结果示例:

{
  "success": true,
  "message": "OK",
  "code": 0,
  "lifeCycleTime": 3,
  "executionTime": 2,
  "value": {
    "id": 10,
    "task_id": "m-20200904-3",
    "task_type": 2,
    "task_data_type": 3,
    "start_time": 1586491785000,
    "end_time": 1586491785000,
    "task_result": 0,
    "remark": "存在不一样"
  }
}

参考链接