0%

在开始之前

关于本教程

新的输入/输出 (NIO) 库是在 JDK 1.4 中引入的。NIO 弥补了原来的 I/O 的不足,它在标准 Java 代码中提供了高速的、面向块的 I/O。通过定义包含数据的类,以及通过以块的形式处理这些数据,NIO 不用使用本机代码就可以利用低级优化,这是原来的 I/O 包所无法做到的。

在本教程中,我们将讨论 NIO 库的几乎所有方面,从高级的概念性内容到底层的编程细节。除了学习诸如缓冲区和通道这样的关键 I/O 元素外,您还有机会看到在更新后的库中标准 I/O 是如何工作的。您还会了解只能通过 NIO 来完成的工作,如异步 I/O 和直接缓冲区。

在本教程中,我们将使用展示 NIO 库的不同方面的代码示例。几乎每一个代码示例都是一个大的 Java 程序的一部分,您可以在 参考资料 中找到这个 Java 程序。在做这些练习时,我们推荐您在自己的系统上下载、编译和运行这些程序。在您学习了本教程以后,这些代码将为您的 NIO 编程努力提供一个起点。

本教程是为希望学习更多关于 JDK 1.4 NIO 库的知识的所有程序员而写的。为了最大程度地从这里的讨论中获益,您应该理解基本的 Java 编程概念,如类、继承和使用包。多少熟悉一些原来的 I/O 库(来自 java.io.* 包)也会有所帮助。

虽然本教程要求掌握 Java 语言的工作词汇和概念,但是不需要有很多实际编程经验。除了彻底介绍与本教程有关的所有概念外,我还保持代码示例尽可能短小和简单。目的是让即使没有多少 Java 编程经验的读者也能容易地开始学习 NIO。

阅读全文 »

BeanFactory与FactoryBean,相信很多刚翻看Spring源码的同学跟我一样很好奇这俩货怎么长得这么像,分别都是干啥用的。BeanFactory是Spring中Bean工厂的顶层接口,也是我们常说的SpringIOC容器,它定下了IOC容器的一些规范和常用方法并管理着Spring中所有的Bean,今天我们不讲它,我们看一下后面那个FactoryBean。

先说下FactoryBean和其作用再开始分析:首先它是一个Bean,但又不仅仅是一个Bean。它是一个能生产或修饰对象生成的工厂Bean,类似于设计模式中的工厂模式和装饰器模式。它能在需要的时候生产一个对象,且不仅仅限于它自身,它能返回任何Bean的实例。

阅读全文 »

开发准备

依赖

新建Maven工程,引入依赖

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.apache.rocketmq/rocketmq-client -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-client</artifactId>
<version>4.5.0</version>
</dependency>
  • 这里我还引入了一个rocketmq-example,这里面的示例代码和官方文档是一直的,可以直接参考
1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.apache.rocketmq/rocketmq-example -->
<dependency>
<groupId>org.apache.rocketmq</groupId>
<artifactId>rocketmq-example</artifactId>
<version>4.5.0</version>
</dependency>
  • 前一步的RocketMQ服务搭建并运行无误就可以进入Java编码了

命令

  • 这里重点说一下,防火墙请放行9876端口,如果可以请把防火墙彻底关掉。
  • 贴上CentOS7中 firewalld 的基本使用命令:
    • 启动:systemctl start firewalld
    • 关闭:systemctl stop firewalld
    • 查看状态:systemctl status firewalld
    • 开机禁用 :systemctl disable firewalld
    • 开机启用 :systemctl enable firewalld
    • 放行9876端口:firewall-cmd --zone=public --add-port=9876/tcp --permanent(–permanent永久生效,没有此参数重启后失效)
    • 重新载入:firewall-cmd --reload(修改端口后需要重新载入)
    • 查看9876端口:firewall-cmd --zone= public --query-port=9876/tcp
    • 删除9876端口:firewall-cmd --zone= public --remove-port=9876/tcp --permanent

文档

  • 本篇代码参照自官方文档及 rocketmq-example 中的示例代码
  • 官方文档及快速上手示例地址:https://rocketmq.apache.org/docs/simple-example/
  • Producer示例代码路径:org.apache.rocketmq.example.quickstart.Producer (需导入 rocketmq-example 依赖)
  • Customer示例代码路径:org.apache.rocketmq.example.quickstart.Customer (需导入 rocketmq-example 依赖)

阅读全文 »

消息队列作为高并发系统的核心组件之一,能够帮助业务系统解构提升开发效率和系统稳定性。最近公司的项目也是用上了RocketMQ,所以这里记录一下RocketMQ环境安装部署过程。

环境准备

我们假设你已经设置好如下环境,没有的先自行安装环境,这里不做展开

  • Centos7:我这里用的是阿里云服务器,Centos7,内核:3.10.0-693.2.2.el7.x86_64
  • JDK1.8:JDK版本:JDK_1.8.0_201_64-Bit
  • Maven:Apache Maven 3.6.0
  • unzip:解压工具,用来解压安装包,没有该工具可直接使用 yum install unzip -y 安装

# 文档及代码
# 安装方式一:二进制直接运行
  • 二进制文件:http://mirrors.shu.edu.cn/apache/rocketmq/4.5.0/rocketmq-all-4.5.0-bin-release.zip

  • 下载二进制文件:wget http://mirrors.shu.edu.cn/apache/rocketmq/4.5.0/rocketmq-all-4.5.0-bin-release.zip

  • 解压:unzip rocketmq-all-4.5.0-bin-release.zip

  • 进入解压后的二进制文件目录:cd rocketmq-all-4.5.0-bin-release

  • 看到以下目录结构:

    1
    2
    3
    4
    5
    6
    7
    drwxr-xr-x 2 root root  4096 Mar 29 17:37 benchmark
    drwxr-xr-x 3 root root 4096 Mar 29 17:37 bin
    drwxr-xr-x 6 root root 4096 Mar 29 17:37 conf
    drwxr-xr-x 2 root root 4096 Mar 29 17:37 lib
    -rw-r--r-- 1 root root 17336 Mar 28 19:52 LICENSE
    -rw-r--r-- 1 root root 1337 Mar 28 19:53 NOTICE
    -rw-r--r-- 1 root root 2521 Mar 28 19:53 README.md

    启动NameServer服务

  • 后台启动Name Server服务:nohup sh bin/mqnamesrv &

  • 查看启动日志:tail -f ~/logs/rocketmqlogs/namesrv.log

阅读全文 »

本文转载自:蚩尤后裔 https://blog.csdn.net/wangmx1993328/article/details/81510782

RocketMQ 简介

RocketMQ 特性

  • RockatMQ 是一款分布式消息引擎
  • 低延迟、高并发:99.6%以上的响应延迟在1毫秒以内
  • 面向金融:满足跟踪和审计的高可用性
  • 工业级适用:可确保万亿量级的消息发送
  • 中立性:支持多种消息传递协议,如 JMS 和 OpenMessaging
  • 性能可靠:给予足够的磁盘空间,消息可以累积存放而没有性能损失。
  • 支持发布/订阅(Pub/Sub)和点对点(P2P)消息模型
  • 在一个队列中可靠的先进先出(FIFO)和严格的顺序传递
  • 支持拉(pull)和推(push)两种消息模式
  • 单一队列百万消息的堆积能力
  • 分布式高可用的部署架构,满足至少一次消息传递语义
  • 提供 docker 镜像用于隔离测试和云集群部署
  • 提供配置、指标和监控等功能丰富的 Dashboard
阅读全文 »

今天发生了一件非常突然的事情,突然得我措手不及没有做好任何心理准备。事起肯定有因,也怪我自己的粗心大意造成了今天的后果,所以今天也算是给了我一个非常深刻的教训吧。以上只是我个人发的几句牢骚,跟本文无关。本篇博客是周末两天就准备好了的,整理了下趁今天贴出来,后面我要调整调整,博客更新可能会停滞一段时间。吃一堑长一智,愿自己变得越来越好。2019年3月11日19:25:51

设计模式之单例模式

单例模式(Singleton Pattern)是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。单例模式是创建型模式。单例模式在现实生活中应用也非常广泛。
例如,国家主席、公司 CEO、部门经理等。在 J2EE 标准中,ServletContext、ServletContextConfig 等;在 Spring 框架应用中 ApplicationContext;数据库的连接池也都是单例形式。

本篇目录

  1. 饿汉式单例
  2. 懒汉式单例
  3. 反射破坏单例
  4. 序列化破坏单例
  5. 注册式单例之容器缓存
  6. 注册式单例之枚举单例
  7. ThreadLocal 线程单例

# 饿汉式单例

先看代码:

1
2
3
4
5
6
7
public class HungrySingleton {
private static final HungrySingleton HUNGRY_SINGLETON = new HungrySingleton();
private HungrySingleton() {}
public static HungrySingleton getInstance() {
return HUNGRY_SINGLETON;
}
}

代码非常简单,使用了static关键字,在类被加载的时候就进行实例化,并私有构造方法,提供一个静态方法返回实例的引用。这里的静态成员变量也可以使用静态代码块进行初始化,如:

1
2
3
static {
HUNGRY_SINGLETON = new HungryStaticSingleton();
}

这种方式简单有效,没有任何形式的锁,所以不存在效率问题。但缺点是不管类有没有被使用,只要被加载就回初始化,会造成资源浪费,当这样的单例非常多的是时候,是需要占用很大的内存空间的。

阅读全文 »

关于SpringBoot使用this.class.getResource()获取文件时遇(cu)到(xin)的(da)坑(yi),这里记录一下。

在使用Springboot开发本博客系统时,在resource目录下增加了一些配置文件,代码中需要读取这些文件,故使用了this.getClass().getResource()获取这些文件。

1
2
String path = this.class.getResource("/config/xxx.properties").getPath();
FileInputStream fis = new FileInputStream(new File(path));

在IDE工具中开发及Debug时一切都正常,但是打成Jar包发布到线上时就会出现java.io.FileNotFoundException

报错很直白的告诉我们是因为文件不存在,仔细检查了文件及代码,而且也确认在IDE工具中一切正常,而且也将打成的Jar包解压确认文件确实打包进去了。

那么为什么会导致打成Jar包就会找不到文件呢?后面仔细查看具体的报错信息:

1
java.io.FileNotFoundException: file:\E:\repo\guitu-blog\target\guitu-blog-1.0.0-SNAPSHOT.jar!\BOOT-INF\classes!\config\xxx.properties

检查路径发现在磁盘确实不存在这样一条路径,因为路径从 ...\guitu-blog-1.0.0-SNAPSHOT.jar\...开始,后面的文件路径都是打到Jar包中的,磁盘没有后面 ...\BOOT-INF\classes!\config\xxx\xxx.properties这样的目录;

在Jar包中的文件在磁盘是没有实际路径的,所以通过这时候可以通过 this.getClass().getResource() 无法获取文件。
此时可以通过 this.getClass().getResourceAsStream("/config/xxx.properties") 能够正常获取到文件流。

1
InputStream is = ComController.class.getResourceAsStream("/config/xxx.properties");

同理 this.getClass().getClassLoader().getResourceAsStream("config/xxx.properties") 也能够获取到文件流。

注意这两种方式获取流时传入的参数,一个以 "/" 开头,一个不是以 "/" ,具体的区别请查阅我的另一篇博客 关于获取资源文件,Class.getResource 和 ClassLoader.getResource 的区别

在Java中经常会需要读取各种各样的配置文件,在获取资源时,一般会用到 Class.getResource() 或 ClassLoader.getResource() ; 那么这两种方式在获取资源文件时有什么相同或者不同的地方呢?

在Java中经常会需要读取各种各样的配置文件,在获取资源时,一般会用到 Class.getResource()ClassLoader.getResource() ;

那么这两种方式在获取资源文件时有什么相同或者不同的地方呢?

先贴上代码目录结构:

1
2
3
4
5
6
7
8
9
10
11
┌─src
│ └─main
│ └─java
│ └─com.guitu18.blog
│ ├─classpath
│ │ └─GetResourceTest.java
│ └─SpringbootApplication.java
└─resource
├─mapper
│ └─BlogDao.xml
└─confog.properties

Class.getResource()

测试代码,先看 this.getClass().getResource()
代码的输出结果我直接贴在代码的上一行了,下同。

1
2
3
4
5
6
7
@Test
public void classGetResource() {
// file:/E:/repo/guitu-blog/target/test-classes/com/guitu18/blog/classpath/
System.out.println(this.getClass().getResource(""));
// file:/E:/repo/guitu-blog/target/test-classes/
System.out.println(this.getClass().getResource("/"));
}

可以看出,getResource("") 获取的是当前类所在包的路径,而 getResource("/") 获取的是 classpath 根路径;

继续测试,我们获取目录下的文件:

阅读全文 »

新版博客系统上线!赶在新年之前,也是赶在春节放假之前哈哈! 零零散散折腾整整两个月时间,全新版本的博客系统终于是可以上线了,新版博客采用Java开发,分为前后两套系统独立运行。 前台系统提供博客正常的访问、评论、访问日志、邮件通知等功能,后台系统提供博客的管理,审核、发布以及管理日志。

全新出发

新版博客系统上线!赶在新年之前,也是赶在春节放假之前哈哈!

零零散散折腾整整两个月时间,全新版本的博客系统终于是可以上线了,新版博客采用Java开发,分为前后两套系统独立运行。

前台系统提供博客正常的访问、评论、访问日志、邮件通知等功能,后台系统提供博客的管理,审核、发布以及管理日志。两套系统共用数据库,但独立运行,互不影响,后台系统不启动,前台所有功能也能正常使用。

新版博客没有改变原博客的前台模板,现在访问新版在视觉上没有任何变化,但是后台代码已经完全不是一个东西了,后续会慢慢做一些个性化的功能。

博客记事

搭博客其实我也是折腾过好几次开源系统了,从最早WordPress,到后面尝试Typecho,甚至Discuz我都尝试过,各种折腾,最后换成帝国CMS之后一直用到现在。

之所以想自己折腾一个博客系统也是想解决自己在使用开源博客系统时的遇到的一些痛点。 之前折腾的这些开源系统都是使用PHP编写的,本人从事Java开发,对PHP了解太少,都是现学现用,简单改一改还行,增删功能这些操作是弄不来的。有时候我很想增加一下小功能,但是需要投入不少精力去学习PHP才能完成,反正都是花时间,干脆使用Java开发一套得了,还能练练手。于是,想到就是干,动工。

翻看我的SVN记录,第一次ADD博客代码的时间是2018年11月29日21:23:22,算上之前搭框架的时间,应该两个月余几天了,期间工作、学习和私人活动占去不少时间,只能挤一些零碎的时间折腾一下,时间还是拖得有点久了。

现在的博客系统,前台部分基本已经都完成了,后台部分仅做了列表出来,博客发布和管理,博主回复等功能还没完成。现在的博客数据是写了一套迁移代码,从帝国CMS无缝迁移过来的。趁年前先上线了,后台其余功能只能等到年后再做了。

2019,再接再厉

明天,不,已经凌晨一点多了应该算今天了,今天上完最后一天班明天就开始春节放假了。明天28号坐火车回家过年,想想还是有点小激动。

新的一年,也要给自己定一些新的计划了。2019,再接再厉。

上篇分析的是JDK动态代理实现原理,这篇是一个自实现的动态代理案例,这一篇我们自定义代理Proxy,代理业务需要实现的Handler接口,以及类加载器ClassLoader;最终我们以自己写的代码去生成代理类的代码,再用代理类的代码去代理执行我们的业务代码,完成一套标准的动态代理;

本博客关于Java动态代理相关内容直达链接:

  1. JDK动态代理浅析
  2. Cglib动态代理浅析
  3. JDK动态代理深入理解分析并手写简易JDK动态代理(上)
  4. JDK动态代理深入理解分析并手写简易JDK动态代理(下)

上篇分析的是JDK动态代理实现原理,这个下篇是一个自实现的动态代理案例,这一篇我们自定义代理Proxy,代理业务需要实现的Handler接口,以及类加载器ClassLoader;最终我们以自己写的代码去生成代理类的代码,再用代理类的代码去代理执行我们的业务代码,完成一套标准的动态代理流程;

首先我们分析实现代理需要什么,下面是Proxy生成代理类的newProxyInstance()方法:

1
Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

一个代理类Proxy,一个ClassLoader,一个业务类实现的接口数组,一个InvocationHandler;
把这里的步骤拆分一下就是下面的两步:

1
2
1. Proxy其实就是根据传递给它的参数Class<?>[] interfaces去生成代理类$Proxy0;  
2. 用ClassLoader loader去加载生成的这个代理类$Proxy0,然后返回$Proxy0实例的引用;

现在一步步来做,在Proxy中,我们大致可以细分为4步:

1
2
3
4
1. 动态生成代理类的源代码.java文件,并写入到磁盘;
2. 把生成的.java文件编译成.class文件;
3. 把编译的.class文件加载到JVM
4. 返回动态生成的代理对象;

那么GuituDynamicProxy类完成后的代码如下(相当于Proxy):

阅读全文 »