文章目录

平常心博客

平常心的日常积累

标签: 每日一搏 (70)

【转载】Netty学习(三)-Netty重要接口讲解

上一节我们写了一个HelloWorld,对于Netty的运行有了一定的了解,知道Netty是如何启动客户端和服务器端。这一节我们简要的讲解一下几个重要的接口,初步探讨Netty的运行机制,当然刚学Netty就深入原理肯定是很枯燥的,所以我们就点到为止。

1. ChannelPipeLine和ChannelHandler

在上一篇中我们在ChannelInitializer类的initChannel方法中使用了ChannelPipeline,然后在ChannelPipeline中使用了handler来处理业务逻辑。

ChannelPipeline是ChannelHandler的容器,它负责ChannelHandler的管理和事件拦截与调度。Netty的ChannelPipeline和ChannelHandler机制类似于Servlet 和Filter 过滤器,这类拦截器实际上是职责链模式的一种变形,主要是为了方便事件的拦截和用户业务逻辑的定制。

Netty的channel运用机制和Filter过滤器机制一样,它将Channel 的数据管道抽象为ChannelPipeline. 消息在ChannelPipeline中流动和传递。ChannelPipeline 持有I/O事件拦截器ChannelHandler 的链表,由ChannelHandler 对I/0 事件进行拦截和处理,可以方便地通过新增和删除ChannelHandler 来实现小同的业务逻辑定制,不需要对已有的ChannelHandler进行修改,能够实现对修改封闭和对扩展的支持。

通过一张图我们来看一下他们之间的关系:
c17caf0a1f72444ca8d67eeb5df1c713-I6jciGg.png

一个Channel中包含一个ChannelPipeline,用来处理Channel中的事件,一个ChannelPipeline中可以包含很多个handler,第二节的示例代码中我们也看到了,使用各种handler来处理通信信息。

同时我们也注意到在hadler中继承了ChannelInboundHandlerAdapter类并实现了他的一些方法,比如:channelRead,channelActive,channelInactive等等,我们看到这些方法中都有一个参数:ChannelHandlerContext ctx。这个ChannelHandlerContext就是handler的上下文对象,有了这个ChannelHandlerContext你就获得了一切,你可以获得通道,获得事件的控制权。

【转载】Netty学习(二)-Helloworld Netty

这一节我们来讲解Netty,使用Netty之前我们先了解一下Netty能做什么,无为而学,岂不是白费力气!

1.使用Netty能够做什么

  1. 开发异步、非阻塞的TCP网络应用程序;
  2. 开发异步、非阻塞的UDP网络应用程序;
  3. 开发异步文件传输应用程序;
  4. 开发异步HTTP服务端和客户端应用程序;
  5. 提供对多种编解码框架的集成,包括谷歌的Protobuf、Jboss marshalling、Java序列化、压缩编解码、XML解码、字符串编解码等,这些编解码框架可以被用户直接使用;
  6. 提供形式多样的编解码基础类库,可以非常方便的实现私有协议栈编解码框架的二次定制和开发;
  7. 基于职责链模式的Pipeline-Handler机制,用户可以非常方便的对网络事件进行拦截和定制;
  8. 所有的IO操作都是异步的,用户可以通过Future-Listener机制主动Get结果或者由IO线程操作完成之后主动Notify结果,用户的业务线程不需要同步等待;
  9. IP黑白名单控制;
  10. 打印消息码流;
  11. 流量控制和整形;
  12. 性能统计;
  13. 基于链路空闲事件检测的心跳检测

2. Netty常用类讲解

在这里我们就一些我们常用到的类做大致的讲解,然后再写入门程序的时候大致知道每一行都讲了什么。

EventLoop,EventLoopGroup

EventLoop目的是为Channel处理IO操作,一个EventLoop可以为多个Channel服务,EventLoopGroup会包含多个EventLoop。

BootStrap,ServerBootstrap

一个Netty应用通常由一个Bootstrap开始,它主要作用是配置整个Netty程序,串联起各个组件。

ChannelInitializer

当一个链接建立时,我们需要知道怎么来接收或者发送数据,当然,我们有各种各样的Handler实现来处理它,那么ChannelInitializer便是用来配置这些Handler,它会提供一个ChannelPipeline,并把Handler加入到ChannelPipeline。

Handler

为了支持各种协议和处理数据的方式,便诞生了Handler组件。Handler主要用来处理各种事件,这里的事件很广泛,比如可以是连接、数据接收、异常、数据转换等。

ChannelInboundHandler

一个最常用的Handler。这个Handler的作用就是处理接收到数据时的事件,也就是说,我们的业务逻辑一般就是写在这个Handler里面的,ChannelInboundHandler就是用来处理我们的核心业务逻辑。

Future

在Netty中所有的IO操作都是异步的,因此,你不能立刻得知消息是否被正确处理,但是我们可以过一会等它执行完成或者直接注册一个监听,具体的实现就是通过Future和ChannelFutures,他们可以注册一个监听,当操作执行成功或失败时监听会自动触发。总之,所有的操作都会返回一个ChannelFuture。

【转载】Netty学习(一)-为什么选择Netty 有更新!

前面我们简单学习了NIO。我们知道java的I/O模型一共有四种,分别是:传统的BIO,伪异步I/O,NIO和AIO。为了澄清概念和分清区别,我们还是先简单的介绍一下他们的概念,然后再去比较优劣。以及探讨我们为什么使用netty。

1.概念澄清

1.1 BIO

BIO,即Blocking I/O。网络编程的基本模型是Client/Server 模型,也就是两个进程之间进行相互通信,其中服务端提供位置信息(绑定的Ip 地址和监听端口) ,客户端通过连接操作向服务端监听的地址发起连接请求,通过三次握手建立连接,如果连接建在成功,双方就可以通过网络套接字( Socket ) 进行通信。在基于传统同步阻塞模型开发中, ServerSocket 负责绑定IP 地址,启动监听端口:Socket 负责发起连接操作。连接成功之后,双方通过输入和输出流进行同步阻塞式通信

BIO通信模型图:
bd0c541302664b5ba092f5e7fecf46fb-y9lBJlB.png

解释一下上图:

采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端的连接,它接收到客户端连接请求之后为每个客户端创建一个新的线程进行链路处理,处理完成之后,通过输出流返回应答给客户端, 统程销毁。这就是典型的一请求一回答通信模型。

对于这种IO模型我们知道:用户线程发出IO请求之后,内核会去查看数据是否就绪,如果没有就绪就会等待数据就绪,而用户线程就会处于阻塞状态,用户线程交出CPU。当数据就绪之后,内核会将数据拷贝到用户线程,并返回结果给用户线程,用户线程才解除block状态。即在读写数据过程中会发生阻塞现象。

【转载】Spring Boot干货系列:(十二)Spring Boot使用单元测试

前言

这次来介绍下Spring Boot中对单元测试的整合使用,本篇会通过以下4点来介绍,基本满足日常需求

  • Service层单元测试
  • Controller层单元测试
  • 新断言assertThat使用
  • 单元测试的回滚

正文

Spring Boot中引入单元测试很简单,依赖如下:

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-test</artifactId>
	<scope>test</scope>
</dependency>

本篇实例Spring Boot版本为1.5.9.RELEASE,引入spring-boot-starter-test后,有如下几个库:
• JUnit — The de-facto standard for unit testing Java applications.
• Spring Test & Spring Boot Test — Utilities and integration test support for Spring Boot applications.
• AssertJ — A fluent assertion library.
• Hamcrest — A library of matcher objects (also known as constraints or predicates).
• Mockito — A Java mocking framework.
• JSONassert — An assertion library for JSON.
• JsonPath — XPath for JSON.

3239cbea780149478b0f704732e6a6dd-58118811360f131a64824a4.png

【转载】Spring Boot干货系列:(十一)数据存储篇-Spring Boot整合Mybatis通用Mapper插件

前言

上次介绍了Spring Boot中Mybatis的简单整合,本篇深入来结合通用Mapper、Mybatis Geneator以及分页PageHelper来打造适合企业开发的模板框架。

正文

项目框架还是跟上一篇一样使用Spring Boot的ace后端模板,不过最近在使用vue,所以前端引用了vue进来改写,代码变得更加简洁。

项目配置:

Spring Boot: 1.5.9.RELEASE
Maven: 3.5
Java: 1.8
Thymeleaf: 3.0.7.RELEASE
Vue.js: v2.5.11

数据源依赖

这里我们还是使用阿里巴巴的druid来当数据库连接池,发现这个有对应的监控界面,我们可以开启。
druid官方文档:https://github.com/alibaba/druid/wiki/常见问题

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
</dependency>

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid</artifactId>
	<version>1.0.19</version>
</dependency>

对应的application.properties配置:

## 数据库访问配置
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name = com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=utf-8
spring.datasource.username = root
spring.datasource.password = root

# 下面为连接池的补充设置,应用到上面所有数据源中
# 初始化大小,最小,最大
spring.datasource.initialSize=5
spring.datasource.minIdle=5
spring.datasource.maxActive=20
# 配置获取连接等待超时的时间
spring.datasource.maxWait=60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
spring.datasource.timeBetweenEvictionRunsMillis=60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
spring.datasource.minEvictableIdleTimeMillis=300000
spring.datasource.validationQuery=SELECT 1 FROM DUAL
spring.datasource.testWhileIdle=true
spring.datasource.testOnBorrow=false
spring.datasource.testOnReturn=false
# 打开PSCache,并且指定每个连接上PSCache的大小
spring.datasource.poolPreparedStatements=true
spring.datasource.maxPoolPreparedStatementPerConnectionSize=20
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
spring.datasource.filters=stat,wall,log4j
# 合并多个DruidDataSource的监控数据
#spring.datasource.useGlobalDataSourceStat=true

【转载】Spring Boot干货系列:(十)开发常用的热部署方式汇总

前言

平时开发Sprig Boot的时候,经常改动个小小的地方就要重新启动项目,这无疑是一种很差的体验。在此,博主收集了3种热部署的方案供大家选择。

正文

目前博主用过的有三种:

  • Spring Loaded
  • spring-boot-devtools
  • JRebel插件

博主开发环境

  • 系统:win10
  • 开发工具:IDE:IntelliJ IDEA 2017.1
  • spring-boot版本:1.5.3RELEASE
  • JDK:1.8

Spring Loaded 实现热部署

Spring Loaded是一个用于在JVM运行时重新加载类文件更改的JVM代理,Spring Loaded允许你动态的新增/修改/删除某个方法/字段/构造方法,同样可以修改作用在类/方法/字段/构造方法上的注解.也可以新增/删除/改变枚举中的值。

spring-loaded是一个开源项目,项目地址:https://github.com/spring-projects/spring-loaded

Spring Loaded有两种方式实现,分别是Maven引入依赖方式或者添加启动参数方式

Maven依赖方式

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <dependencies>
        <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>springloaded</artifactId>
        <version>1.2.6.RELEASE</version>
        </dependency>
    </dependencies>
</plugin>

【转载】Spring Boot干货系列:(九)数据存储篇-SQL关系型数据库之MyBatis的使用

前言

上篇我们介绍了Spring Boot对传统JdbcTemplate的集成,这次换一下,介绍下Spring Boot中如何集成MyBatis。这里分别介绍注解方式以及XML方式的整合。喜欢哪种方式自己选择。

正文

项目框架还是跟上一篇一样使用Spring Boot的ace后端模板,你可以基于它来跟着博主一起来调整代码,如果没看过上一篇,那就下载本篇源码研究吧。

跟上篇一样先添加基础的依赖和数据源。

添加依赖

这里需要添加mybatis-spring-boot-starter依赖跟mysql依赖

<!--最新版本,匹配spring Boot1.5 or higher-->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>1.3.0</version>
</dependency>

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

这里不引入spring-boot-starter-jdbc依赖,是由于mybatis-spring-boot-starter中已经包含了此依赖。

【转载】Spring Boot干货系列:(八)数据存储篇-SQL关系型数据库之JdbcTemplate的使用

前言

前面几章介绍了一些基础,但都是静态的,还不足以构建一个动态的应用。本篇开始就要介绍数据交互了,为了演示效果更加好,博主花了大把时间整合了一个后端模板框架,基于Bootstrap3的ACE模板,并实现了一个基本的增删改查分页功能。让我们一起动手,学技术的同时,顺便把我们的项目完善起来,这样跟着博主学到最后,你就有了一个属于自己的Spring Boot项目啦。

正文

本文介绍在Spring Boot基础下配置数据源和通过JdbcTemplate编写数据访问的示例。

添加依赖

这里需要添加spring-boot-starter-jdbc依赖跟mysql依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

数据源配置

在src/main/resources/application.properties中配置数据源信息。

spring.datasource.url = jdbc:mysql://localhost:3306/spring?useUnicode=true&characterEncoding=utf-8
spring.datasource.username = root
spring.datasource.password = root
spring.datasource.driver-class-name = com.mysql.jdbc.Driver

【转载】Spring Boot干货系列:(七)默认日志logback配置解析

前言

今天来介绍下Spring Boot如何配置日志logback,我刚学习的时候,是带着下面几个问题来查资料的,你呢

  • 如何引入日志?
  • 日志输出格式以及输出方式如何配置?
  • 代码中如何使用?

正文

Spring Boot在所有内部日志中使用Commons Logging,但是默认配置也提供了对常用日志的支持,如:Java Util LoggingLog4J, Log4J2Logback。每种Logger都可以通过配置使用控制台或者文件输出日志内容。

默认日志Logback

SLF4J——Simple Logging Facade For Java,它是一个针对于各类Java日志框架的统一Facade抽象。Java日志框架众多——常用的有java.util.logging, log4j, logbackcommons-logging, Spring框架使用的是Jakarta Commons Logging API (JCL)。而SLF4J定义了统一的日志抽象接口,而真正的日志实现则是在运行时决定的——它提供了各类日志框架的binding。

Logback是log4j框架的作者开发的新一代日志框架,它效率更高、能够适应诸多的运行环境,同时天然支持SLF4J。

默认情况下,Spring Boot会用Logback来记录日志,并用INFO级别输出到控制台。在运行应用程序和其他例子时,你应该已经看到很多INFO级别的日志了。
a6ae61034fa946db88a0e8f258cbb6de-sringboot71.png

从上图可以看到,日志输出内容元素具体如下:

  • 时间日期:精确到毫秒
  • 日志级别:ERROR, WARN, INFO, DEBUG or TRACE
  • 进程ID
  • 分隔符:--- 标识实际日志的开始
  • 线程名:方括号括起来(可能会截断控制台输出)
  • Logger名:通常使用源代码的类名
  • 日志内容

【转载】Spring Boot干货系列:(六)静态资源和拦截器处理

前言

本章我们来介绍下SpringBoot对静态资源的支持以及很重要的一个类WebMvcConfigurerAdapter。

正文

前面章节我们也有简单介绍过SpringBoot中对静态资源的默认支持,今天详细的来介绍下默认的支持,以及自定义扩展如何实现。

默认资源映射

Spring Boot 默认为我们提供了静态资源处理,使用 WebMvcAutoConfiguration 中的配置各种属性。
建议大家使用Spring Boot的默认配置方式,提供的静态资源映射如下:

  • classpath:/META-INF/resources
  • classpath:/resources
  • classpath:/static
  • classpath:/public

【转载】Spring Boot干货系列:(五)开发Web应用之JSP篇

前言

上一篇介绍了Spring Boot中使用Thymeleaf模板引擎,今天来介绍一下如何使用SpringBoot官方不推荐的jsp,虽然难度有点大,但是玩起来还是蛮有意思的。

正文

先来看看整体的框架结构,跟前面介绍Thymeleaf的时候差不多,只是多了webapp这个用来存放jsp的目录,静态资源还是放在resources的static下面。
f7f56007c70f47b0ae4854c5efbfc5c0-springboot51.jpg

引入依赖

<!--WEB支持-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--jsp页面使用jstl标签-->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
</dependency>

<!--用于编译jsp-->
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <scope>provided</scope>
</dependency>

【转载】Spring Boot干货系列:(四)开发Web应用之Thymeleaf篇

前言

Web开发是我们平时开发中至关重要的,这里就来介绍一下Spring Boot对Web开发的支持。

正文

Spring Boot提供了spring-boot-starter-web为Web开发予以支持,spring-boot-starter-web为我们提供了嵌入的Tomcat以及Spring MVC的依赖。

项目结构推荐

一个好的项目结构会让你开发少一些问题,特别是Spring Boot中启动类要放在root package下面,我的web工程项目结构如下:
6a674c78965447a0ab3ade162029e0c2-springboot41.jpg

  • root package结构:com.dudu
  • 应用启动类Application.java置于root package下,这样使用@ComponentScan注解的时候默认就扫描当前所在类的package
  • 实体(Entity)置于com.dudu.domain包下
  • 逻辑层(Service)置于com.dudu.service包下
  • controller层(web)置于com.dudu.controller层包下
  • static可以用来存放静态资源
  • templates用来存放默认的模板配置路径

【转载】Spring Boot干货系列:(三)启动原理解析

前言

前面几章我们见识了SpringBoot为我们做的自动配置,确实方便快捷,但是对于新手来说,如果不大懂SpringBoot内部启动原理,以后难免会吃亏。所以这次博主就跟你们一起一步步揭开SpringBoot的神秘面纱,让它不在神秘。

正文

我们开发任何一个Spring Boot项目,都会用到如下的启动类

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

从上面代码可以看出,Annotation定义(@SpringBootApplication)和类定义(SpringApplication.run)最为耀眼,所以要揭开SpringBoot的神秘面纱,我们要从这两位开始就可以了。

【转载】Spring Boot干货系列:(二)配置文件解析

前言

上一篇介绍了Spring Boot的入门,知道了Spring Boot使用“习惯优于配置”(项目中存在大量的配置,此外还内置了一个习惯性的配置,让你无需手动进行配置)的理念让你的项目快速运行起来。所以,我们要想把Spring Boot玩的溜,就要懂得如何开启各个功能模块的默认配置,这就需要了解Spring Boot的配置文件application.properties。

正文

Spring Boot使用了一个全局的配置文件application.properties,放在src/main/resources目录下或者类路径的/config下。Sping Boot的全局配置文件的作用是对一些默认配置的配置值进行修改。

接下来,让我们一起来解开配置文件的面纱。

注:如果你工程没有这个application.properties,那就在src/main/java/resources目录下新建一个。

自定义属性

application.properties提供自定义属性的支持,这样我们就可以把一些常量配置在这里:

com.dudu.name="嘟嘟MD"
com.dudu.want="祝大家鸡年大吉吧"

然后直接在要使用的地方通过注解@Value(value=”${config.name}”)就可以绑定到你想要的属性上面

【转载】Spring Boot干货系列:常用属性汇总

附录A.常用应用程序属性

摘自:http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html

可以在application.properties/application.yml文件中或作为命令行开关指定各种属性。本节提供了常用的Spring Boot属性列表,以及对使用它们的底层类的引用。

属性贡献可以来自您的类路径上的其他jar文件,因此您不应该考虑这是一个详尽的列表。定义您自己的属性也是完全合法的。
此示例文件仅作为指南。不要将整个内容复制/粘贴到您的应用程序中;而只是选择你需要的属性。

【转载】Spring Boot干货系列:(一)优雅的入门篇

前言

Spring一直是很火的一个开源框架,在过去的一段时间里,Spring Boot在社区中热度一直很高,所以决定花时间来了解和学习,为自己做技术储备。

正文

首先声明,Spring Boot不是一门新技术,所以不用紧张。从本质上来说,Spring Boot就是Spring,它做了那些没有它你也会去做的Spring Bean配置。它使用“习惯优于配置”(项目中存在大量的配置,此外还内置了一个习惯性的配置,让你无需手动进行配置)的理念让你的项目快速运行起来。使用Spring Boot很容易创建一个独立运行(运行jar,内嵌Servlet容器)、准生产级别的基于Spring框架的项目,使用Spring Boot你可以不用或者只需要很少的Spring配置。

Spring Boot精要

Spring将很多魔法带入了Spring应用程序的开发之中,其中最重要的是以下四个核心。

  • 自动配置:针对很多Spring应用程序常见的应用功能,Spring Boot能自动提供相关配置
  • 起步依赖:告诉Spring Boot需要什么功能,它就能引入需要的库。
  • 命令行界面:这是Spring Boot的可选特性,借此你只需写代码就能完成完整的应用程序,无需传统项目构建。
  • Actuator:让你能够深入运行中的Spring Boot应用程序,一探究竟。

详细的我们就不展开,等你爱上后自然会去深入的了解,后续章节我们会一一展开介绍。接下来让我们开搞吧。我已经迫不及待的要尝尝Spring Boot的味道了。

系统要求

目前Spring Boot正式版为1.5.1.RELEASE默认情况下,Spring Boot 1.5.1.RELEASE需要Java 7和Spring Framework 4.3.6.RELEASE或更高版本,你也可以使用Spring Boot with Java 6和一些额外的配置(不建议),使用Maven(3.2+)或Gradle 2(2.9或更高版本)和3来构建。

虽然你可以使用Java 6或7的Spring Boot,但我们通常推荐Java 8。

所以本博客系列统一使用Java 1.8,Spring Boot 1.5.1.RELEASE以及Maven3.3.9版本。开发工具使用IDEA(强烈推荐,可以看我另外一篇介绍IDEA入门文章,内有官方中文教程:Java人员正确使用 IntelliJ IDEA的方式

【转载】java学习-NIO(五)NIO学习总结以及NIO新特性介绍

我们知道是NIO是在2002年引入到J2SE 1.4里的,很多Java开发者比如我还是不知道怎么充分利用NIO,更少的人知道在Java SE 7里引入了更新的输入/输出 API(NIO.2)。但是对于普通的开发者来说基本的I/O操作就够用了,而NIO则是在处理I/O性能优化方面带来显著性效果。更快的速度则意味着NIO和NIO.2的API暴露了更多低层次的系统操作的入口,这对于开发者而言则意味着更复杂的操作和精巧的程序设计。从前面的几节的讲解来看NIO的操作无不繁琐。要完全掌握还是有点难度的。前面我们讲解了Buffer,Channel,Selector,都是从大的面上去探讨NIO的主要组件。这一节我们则从NIO的特性方面去探讨更细节的一些问题。

1.NIO的新特性

总的来说java 中的IO 和NIO的区别主要有3点:

  1. IO是面向流的,NIO是面向缓冲的;
  2. IO是阻塞的,NIO是非阻塞的;
  3. IO是单线程的,NIO 是通过选择器来模拟多线程的;

NIO在基础的IO流上发展处新的特点,分别是:内存映射技术,字符及编码,非阻塞I/O和文件锁定。下面我们分别就这些技术做一些说明。

2. 内存映射

这个功能主要是为了提高大文件的读写速度而设计的。内存映射文件(memory-mappedfile)能让你创建和修改那些大到无法读入内存的文件。有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问了。将文件的一段区域映射到内存中,比传统的文件处理速度要快很多。内存映射文件它虽然最终也是要从磁盘读取数据,但是它并不需要将数据读取到OS内核缓冲区,而是直接将进程的用户私有地址空间中的一部分区域与文件对象建立起映射关系,就好像直接从内存中读、写文件一样,速度当然快了。

【转载】java学习-NIO(四)Selector

这一节我们将探索选择器(selectors)。选择器提供选择执行已经就绪的任务的能力,这使得多元 I/O 成为可能。就像在第一章中描述的那样,就绪选择和多元执行使得单线程能够有效率地同时管理多个 I/O 通道(channels)。C/C++代码的工具箱中,许多年前就已经有 select()和 poll()这两个POSIX(可移植性操作系统接口)系统调用可供使用了。许过操作系统也提供相似的功能,但对Java 程序员来说,就绪选择功能直到 JDK 1.4 才成为可行的方案。

下面我们来使用选择器:

通过 Selector.open()方法, 我们可以创建一个选择器:

Selector selector = Selector.open();

将 Channel 注册到选择器中:

channel.configureBlocking(false);

SelectionKey key = channel.register(selector, SelectionKey.OP_READ);

注意, 如果一个 Channel 要注册到 Selector 中, 那么这个 Channel 必须是非阻塞的, 即channel.configureBlocking(false);因为 Channel 必须要是非阻塞的, 因此 FileChannel 不能够使用选择器, 因为 FileChannel 都是阻塞的.

注意到, 在使用 Channel.register()方法时, 第二个参数指定了我们对 Channel 的什么类型的事件感兴趣, 这些事件有:

  1. Connect, 即连接事件(TCP 连接), 对应于SelectionKey.OP_CONNECT
  2. Accept, 即确认事件, 对应于SelectionKey.OP_ACCEPT
  3. Read, 即读事件, 对应于SelectionKey.OP_READ, 表示 buffer 可读.
  4. Write, 即写事件, 对应于SelectionKey.OP_WRITE, 表示 buffer 可写.

【转载】java学习-NIO(三)Channel

通道(Channel)是java.nio的第二个主要创新。它们既不是一个扩展也不是一项增强,而是全新、极好的Java I/O示例,提供与I/O服务的直接连接。Channel用于在字节缓冲区和位于通道另一侧的实体(通常是一个文件或套接字)之间有效地传输数据。

channel介绍

通道是访问I/O服务的导管。I/O可以分为广义的两大类别:File I/O和Stream I/O。那么相应地有两种类型的通道也就不足为怪了,它们是文件(file)通道和套接字(socket)通道。我们看到在api里有一个FileChannel类和三个socket通道类:SocketChannel、ServerSocketChannel和DatagramChannel。

通道可以以多种方式创建。Socket通道有可以直接创建新socket通道的工厂方法。但是一个FileChannel对象却只能通过在一个打开的RandomAccessFile、FileInputStream或FileOutputStream对象上调用getChannel( )方法来获取。你不能直接创建一个FileChannel对象。

我们先来看一下FileChannel的用法:

   // 创建文件输出字节流
   FileOutputStream fos = new FileOutputStream("data.txt");
   //得到文件通道
   FileChannel fc = fos.getChannel();
   //往通道写入ByteBuffer
   fc.write(ByteBuffer.wrap("Some text ".getBytes()));
   //关闭流
   fos.close();

   //随机访问文件
   RandomAccessFile raf = new RandomAccessFile("data.txt", "rw");
   //得到文件通道
   fc = raf.getChannel();
   //设置通道的文件位置 为末尾
   fc.position(fc.size()); 
   //往通道写入ByteBuffer
   fc.write(ByteBuffer.wrap("Some more".getBytes()));
   //关闭
   raf.close();

   //创建文件输入流
   FileInputStream fs = new FileInputStream("data.txt");
   //得到文件通道
   fc = fs.getChannel();
   //分配ByteBuffer空间大小
   ByteBuffer buff = ByteBuffer.allocate(BSIZE);
   //从通道中读取ByteBuffer
   fc.read(buff);
   //调用此方法为一系列通道写入或相对获取 操作做好准备
   buff.flip();
   //从ByteBuffer从依次读取字节并打印
   while (buff.hasRemaining()){
       System.out.print((char) buff.get());
   }
   fs.close();

【转载】java学习-NIO(二)Buffer

当我们需要与 NIO Channel 进行交互时, 我们就需要使用到 NIO Buffer, 即数据从 Buffer读取到 Channel 中, 并且从 Channel 中写入到 Buffer 中。缓冲区本质上是一块可以写入数据,然后可以从中读取数据的内存。这块内存被包装成NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。

缓冲区基础

Buffer 类型有:
c89cf59ec0214cf8a8d9299b80b81a6a-co6hMaY.png

缓冲区是包在一个对象内的基础数据的数组,Buffer类相比一般简单数组而言其优点是将数据的内容和相关信息放在一个对象里面,这个对象提供了处理缓冲区数据的丰富的API。

所有缓冲区都有4个属性:capacity、limit、position、mark,并遵循:capacity>=limit>=position>=mark>=0,下面是对这4个属性的解释:

  • Capacity: 容量,即可以容纳的最大数据量;在缓冲区创建时被设定并且不能改变
  • Limit: 上界,缓冲区中当前数据量
  • Position: 位置,下一个要被读或写的元素的索引
  • Mark: 标记,调用mark()来设置mark=position,再调用reset()可以让position恢复到标记的位置即position=mark