Docker基础
DockerDocker 是什么?是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux 或 Windows 机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口。
容器与虚拟机对比: 容器相对来说较为简单运行与操作系统之上消耗资源少而虚拟机完整的模拟了一个操作系统使其消耗资源大且复杂性高不易于调试。
Docker 架构Docker 包括三个基本概念:
镜像(Image): 相当于是一个 root 文件系统。比如官方镜像 ubuntu:16.04 就包含了完整的一套 Ubuntu16.04 最小系统的 root 文件系统。
容器(Container): 镜像和容的关系,就像是面向对象程序设计中的类和实例一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。
仓库(Repository): 仓库可看成一个代码控制中心,用来保存镜像。
Docker三个组件概念:
Docker Client 是用户界面,它支持用户与 Docker Daemon 之间通信。
Docker ...
MyBatis入门
MyBatis入门SqlSessionFactorySqlSessionFactory是Mybatis的核心,SqlSessionFactory的实例可以通过SqlSessionFactoryBuilder获得,而SqlSessionFactoryBuilder会从XML配置文件或Configuration实例中获取配置信息来构建SqlSessionFactory实例。有了SqlSessionFactory就可以获取SqlSession用来执行执行在Mapper.xml中定义好的方法了。下面有一个简单的连接MySQL数据库并查询数据的demo。
工程结构
1234567891011121314main├─java│ └─cn│ └─gmfan│ │ Main.java│ ││ └─domain│ SysUser.java│└─resources │ mybatis-config.xml │ └─mapper SysUserMapper.xml
...
Reactor模式
Reactor模式
Reactor是一个或多个输入事件的处理模式,用于处理并发传递给服务处理程序的服务请求。服务处理程序判断传入请求发生的事件,并将它们同步的分派给关联的请求处理程序。
Reactor之所以高效是因为采用了分而治之和事件驱动设计。分而治之:Reactor模式将处理过程分为多个小任务,每个任务执行一个非阻塞的操作,通常由一个IO事件触发执行。事件驱动:事件驱动设计通常比其他模型更高效,因为他不用针对每个请求启用一条线程,减少了上下文的切换,缺点是必须手动将事件和处理动作绑定。
NIO中总共设计了四种事件:
OP_ACCEPT:服务端监听到一个连接,准备接收
OP_CONNECT:客户端与服务端连接建立成功
OP_READ:读事件就绪,通道有数据可读
OP_WRITE:写事件就绪,可以向通道写入数据
Reactor模式按照职责不同,通常可以把线程分为Reactor线程、IO线程和业务线程:
Reactor线程:轮询通知发生IO的通道,并分派合适的Handler处理
IO线程:执行实际读写操作
业务线程:执行应用程序的业务逻辑
三种Reactor模型单线程React ...
CGLIB基础
CGLIB基础CGLIBCGLIB(Code Generation Library)底层使用了ASM来进行操控字节码,用于生成新的Class文件。CGLIB的原理时代理,动态生成一个要代理类的子类,子类重写要代理类的所有除final方法以外的方法。
12345<dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.3.0</version></dependency>
CGLIB不能代理final方法是因为其本质是通过继承父类并重写父类的方法从而达到生成代理类的目的,并且由于其是继承父类重写父类方法的原理故其无法访问到父类的private方法,也无法代理父类的私有方法。
12345678910111213141516public class A { public static void main(String[] args) { A ...
常见设计模式
常见二十三种设计模式模式定义
模式是在某种情境下,针对某问题的某种解决方案。
情境:是应用某个模式的情况。
问题:是想在某情境下达到的目标,也可以是某情境下的约束。
解决方案:是一个通用的设计用来解决约束达到目标。
分类模式根据目标的不同可以分成三类:创建型、行为型、结构型。模式还可以根据处理的是类或对象分成两类:类模式、对象模式。
目标分类定义
创建型:创建型模式涉及到将对象实例化,这列模式提供一个方法,将客户从所需要的实例化的对象中解耦。
行为型:涉及类和对象如何交互分配职责。
结构型:结构型模式把类或对象组合到更大的结构中。
类模式与对象模式
类模式:类模式的关系是在编译时期建立的。
对象模式:对象模式描述对象之间的关系,而且主要是利用组合定义。对象模式的关系通常在运行时建立,而且更加动态、更有弹性。
目标分类
创建型(五种):工厂方法、抽象工厂、生成器、原型、单例。
结构型模式(7种):适配器、桥接、组合、装饰器、外观、纯元、代理。
行为型模式(11种):责任链、命令、解释器、中介、备忘录、观察者、状态、策略、模板方法、访问者。
创建型(五种)
创建型模式涉及到将对 ...
使用Docker加Nginx配置HTTPS
使用Docker加Nginx配置HTTPS本文将介绍如何将网站HTTP协议升级为HTTPS。部署的网站是Hexo。
前置
服务器已经安装Docker
已经拉取了Nginx镜像
云服务器有安全组的已开放80和443端口
拥有SSL证书并下载了Nginx版本
部署
本文中Nginx使用的版本为1.21.6
部署总共分为以下几个部分
设置挂载目录
将SSL证书上传到服务器的挂载目录
配置Nginx
启动Nginx镜像
设置挂载目录设置挂载目录的目的在于将Docker的虚拟机目录映射到物理机上,例如使用-v /a:/b配合之后,虚拟机访问目录b的资源时,不会直接从b中获取,而是从物理机的a目录下去获取需要访问的资源,读写操作同样。设置挂载目录是在最后启动Nginx镜像执行的
这里我们设置了四个挂载目录:
/etc/localtime:作用是将虚拟机的时间与物理机同步,这个设置在很多应用中都要开启,虚拟机时间不一致可能会导致服务不可用,后台服务的时间与Redis缓存服务的时间不一致,会导致用户频繁掉线。
/etc/nginx:将 ...
Object源码阅读
Object在类层次结构中Object是所有类对对象的根类,并且Object是每个类的超类。
本地方法registerNatives1private static native void registerNatives();
当包含registerNatives()方法的类被加载的时候,注册的方法就是该类所包含的除了registerNatives()方法以外的所有本地方法。
一个Java程序想要调用一个本地方法需要执行两个步骤:
通过System.loadLibrary()将包含本地方法实现的动态文件加载进内存
当Java程序需要调用本地方法时,虚拟机再在加载的动态文件中定位并链接该本地方法,从而执行本地方法。
registerNatives的作用就是取代第二个步骤,让程序主动将本地方法链接到调用方,当Java程序需要调用本地方法时就可以直接调用,而不需要虚拟机再去定位并链接。
使用registerNatives方法的三点好处:
通过registerNatives方法在类被加载的时候就主动将本地方法链接到调用方,比当方法被使用时再由虚拟机来定位和链接更方便有效;
如果本地方法在 ...
String源码阅读
StringString不可变的原因是因为内部使用private final修饰value数组,所以其不可以被继承和重写,并且由于String类没有提供可以修改value数组值的方法所以其不可修改,但是如果使用反射依旧可以修改String对象的值,原因在于final修饰对象时,只是保证被修饰的变量的引用不能再指向其它对象。
方法解释hashCode为什么选择31作为乘积值
1234567891011public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h;}
31 是一个奇质数,如果选择偶数会导致乘积运算 ...
二分查找
二分查找二分查找可以分为查找一个目标值target是否存在和查找一个连续递增的数组中存在着多个相同target的最左边界或者最右边界。
二分查找是否存在target模板下面这个模板中的输入数组是一个递增数组:
1234567891011121314boolean binarySearch(int[] arr,int tar){ int l=0,r=arr.length-1; while(l<=r){//终止条件是left=right+1 int mid=l+r>>>1;//使用无符号位移防止溢出 if(arr[mid]<tar){ l=mid+1; }else if(arr[mid]>tar){ r=mid-1; }else{ return true; } } return false;}
若果 ...
并查集
并查集初识并查集并查集是一种数据结构,其作用是判断两个元素是否属于同于一个集合。例如存在a,b,c,d,e五个元素,其中a,b,c同属于一个集合,d和e属于另一个集合。如果我们实现一种查找,输入a输出0,输入b输出0,输入c输出0那么就可以判断abc是属于同于个集合因为对它们进行查找输出的都是同样的结果,同理输入d输出3,输入e输出3也可以判断它们是同一个集合。
那么并查集需要如何实现呢?同样使用上面的例子,首先对a,b,c,d,e进行标识0,1,2,3,4用它们来作为数组parent的下标并初始化数组元素的值等于其索引值即parent=[0,1,2,3,4],接下来是最为重要的关联操作:我们需要将abc关联起来,只需要使得b指向a,c指向b就可以了。这样查找b的时候就可以顺着指向查找到a,查找c可以顺着指向查找到b最后找到a,a指向a(需要注意的是这个指向操作是有序的)。要实现这个操作只需要将数组parent[1]的值改为0吗,parent[2]的值改为1就可以了,这个时候数组变为了parent=[0,0,1,3,4],例如查找c是否与a同属于一个集合,首先查找c ...