0%

Docker

  • 镜像( Image )
  • 容器( Container )
  • 仓库( Repository )

Docker镜像

    Docker 镜像(Image),就相当于是一个 root 文件系统,它除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。

分层存储

    因为镜像体积庞大,就将其设计成分层存储的架构,所以严格来说镜像由一组文件系统组成。
    镜像构建时,会一层层构建,前一层是后一层的基础。。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。比如,删除前一层文件的操作,实际不是真的删除前一层的文件,而是仅在当前层标记为该文件已删除。在最终容器运行的时候,虽然不会看到这个文件,但是实际上该文件会一直跟随镜像。

阅读全文 »

使用Nacos实现服务注册与发现

什么是 Nacos

官网解释:
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据及流量管理。

Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。 Nacos 是构建以“服务”为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。

个人解释:
微服务管理平台

Nacos优缺点

优点

  • 开箱即用,适用于dubbo,spring cloud
  • AP模型,数据最终一致性
  • 注册中心,配置中心二合一,提供控制台管理
  • 纯国产,久经双十一考验

缺点

  • 刚刚开源不久,社区热度不够,依然存在bug

    优缺点4比1,肯定选它呀,

    阅读全文 »

十大基础排序算法

冒泡排序

  • 基本思路
    对n个数进行排序,每次都是由前一个数跟后一个数比较,每循环一轮, 就可以将最大的数移到数组的最后, 总共循环n-1轮,完成对数组排序。

  • 动图演示

这里写图片描述

  • 编码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public static void sort(int[] arr) {
    if (arr == null)
    return;
    int len = arr.length;
    // i控制循环次数,长度为len的数组只需要循环len-1次,i的起始值为0所以i<len-1
    for (int i = 0; i < len - 1; i++) {
    for (int j = 0; j < len - i - 1; j++) {
    // 如果前一个数比后一个数大,则交换位置将大的数往后放。
    if (arr[j] > arr[j + 1]) {
    int temp = arr[j + 1];
    arr[j + 1] = arr[j];
    arr[j] = temp;
    }
    }
    }
    }

    阅读全文 »

Linux命令大全

linux 系统管理命令

adduser

功能说明:新增用户帐号。
语 法:adduser
补充说明:在 Slackware 中,adduser 指令是个 script 程序,利用交谈的方式取得
输入的用户帐号资料,然后再交由真正建立帐号的 useradd 指令建立新用户,如
此可方便管理员建立用户帐号。在 Red Hat Linux 中,adduser 指令则是 useradd
指令的符号连接,两者实际上是同一个指令。

chfn(change finger information)

功能说明:改变 finger 指令显示的信息。
语 法:chfn [-f <真实姓名>][-h <家中电话>][-o <办公地址>][-p <办公电话>][-uv][帐号名称]
补充说明:chfn 指令可用来更改执行 finger 指令时所显示的信息,这些信息都存
放在/etc 目录里的 asswd 文件里。若不指定任何参数,则 chfn 指令会进入问答式
界面。
参 数

  • -f<真实姓名>或–full-name<真实姓名> 设置真实姓名。

  • -h<家中电话>或–home-phone<家中电话> 设置家中的电话号码。

  • -o<办公地址>或–office<办公地址> 设置办公室的地址。

  • -p<办公电话>或–office-phone<办公电话> 设置办公室的电话号码。

  • -u 或–help 在线帮助。

  • -v 或-version 显示版本信息。

    chsh(change shell)

  • *功能说明**:更换登入系统时使用的 shell。

  • *语 法**:chsh [-luv][-s <shell 名称>][用户名称]

  • *补充说明**:每位用户在登入系统时,都会拥有预设的 shell 环境,这个指令可更
    改其预设值。若不指定任何参数与用户名称,则 chsh 会以应答的方式进行设置。

  • *参 数**:

  • -s<shell 名称>或–shell<shell 名称> 更改系统预设的 shell 环境。

  • -l 或–list-shells 列出目前系统可用的 shell 清单。

  • -u 或–help 在线帮助。

  • -v 或-version 显示版本信息。

阅读全文 »

线程基础

什么是线程?

    几乎每种操作系统都支持进程的概念 —— 进程就是在某种程度上相互隔离的、独立运行的程序。

    线程化是允许多个活动共存于一个进程中的工具。大多数现代的操作系统都支持线程,而且线程的概念以各种形式已存在了好多年。Java 是第一个在语言本身中显式地包含线程的主流编程语言,它没有把线程化看作是底层操作系统的工具。

    有时候,线程也称作轻量级进程。就象进程一样,线程在程序中是独立的、并发的执行路径,每个线程有它自己的堆栈、自己的程序计数器和自己的局部变量。但是,与分隔的进程相比,进程中的线程之间的隔离程度要小。它们共享内存、文件句柄和其它每个进程应有的状态。

    进程可以支持多个线程,它们看似同时执行,但互相之间并不同步。一个进程中的多个线程共享相同的内存地址空间,这就意味着它们可以访问相同的变量和对象,而且它们从同一堆中分配对象。尽管这让线程之间共享信息变得更容易,但您必须小心,确保它们不会妨碍同一进程里的其它线程。

    Java 线程工具和 API 看似简单。但是,编写有效使用线程的复杂程序并不十分容易。因为有多个线程共存在相同的内存空间中并共享相同的变量,所以您必须小心,确保您的线程不会互相干扰。

每个 Java 程序都使用线程

    每个 Java 程序都至少有一个线程 — 主线程。当一个 Java 程序启动时,JVM 会创建主线程,并在该线程中调用程序的 main() 方法。 JVM 还创建了其它线程,您通常都看不到它们 — 例如,与垃圾收集、对象终止和其它 JVM 内务处理任务相关的线程。其它工具也创建线程,如 AWT(抽象窗口工具箱(Abstract Windowing Toolkit))或 Swing UI 工具箱、servlet 容器、应用程序服务器和 RMI(远程方法调用(Remote Method Invocation))

Java 线程的风险

    虽然 Java 线程工具非常易于使用,但当我们创建多线程程序时,应该尽量避免一些风险。
    当多个线程访问同一数据项(如静态字段、可全局访问对象的实例字段或共享集合)时,需要确保它们协调了对数据的访问,这样它们都可以看到数据的一致视图,而且相互不会干扰另一方的更改。
    为了实现这个目的,Java 语言提供了两个关键字:synchronized 和 volatile。当从多个线程中访问变量时,必须确保对该访问正确地进行了同步。对于简单变量,将变量声明成volatile 也许就足够了,但在大多数情况下,需要使用同步。
    如果将要使用同步来保护对共享变量的访问,那么必须确保在程序中所有访问该变量的地方都使用同步。

    虽然线程可以大大简化许多类型的应用程序,过度使用线程可能会危及程序的性能及其可维护性。
    线程消耗了资源。因此,在不降低性能的情况下,可以创建的线程的数量是有限制的。 尤其在单处理器系统中,使用多个线程不会使主要消耗 CPU 资源的程序运行得更快。

阅读全文 »

遇到的坑

  • zookeeper版本不一致问题
  • 虚拟机防火墙没关

如何搭建

Linux上安装zookeeper

因为最近在学习Linux,所以这个东西直接安装在本机的虚拟机上。(你也可以直接在windows上安装和启用zookeeper,道理是一样的,这里不多描述了。)

  • linux命令直接下载

    1
    wget https://archive.apache.org/dist/zookeeper/zookeeper-3.4.8/zookeeper-3.4.8.tar.gz

    这里有个坑,就是版本必须与程序里的依赖对应的版本一致,否则会出bug,而且不容易发现。

  • 解压下载的tar,然后进入zookeeper根目录,新建data和logs俩个目录

  • 用pwd复制目录名字,后面有用

  • 从根目录进入conf目录下,把zoo_sample.cfg命名为zoo.cfg,删除zoo_sample.cfg

  • 编辑zoo.cfg,把里面的dataDir=…删除,加上下面2行代码

    1
    2
    dataDir=/粘贴你自己zookeeper的目录/data
    dataLogDir=/粘贴你自己zookeeper的目录/logs
    阅读全文 »

转发(forward)和重定向(redirect)的区别?

答:forward是容器中控制权的转向,是服务器请求资源,服务器直接访问目标地址的URL,把那个URL 的响应内容读取过来,然后把这些内容再发给浏览器,浏览器根本不知道服务器发送的内容是从哪儿来的,所以它的地址栏中还是原来的地址。redirect就是服务器端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址,因此从浏览器的地址栏中可以看到跳转后的链接地址,很明显redirect无法访问到服务器保护起来资源,但是可以从一个网站redirect到其他网站。forward更加高效,所以在满足需要时尽量使用forward(通过调用RequestDispatcher对象的forward()方法,该对象可以通过ServletRequest对象的getRequestDispatcher()方法获得),并且这样也有助于隐藏实际的链接;在有些情况下,比如需要访问一个其它服务器上的资源,则必须使用重定向(通过HttpServletResponse对象调用其sendRedirect()方法实现)。

JSP有哪些内置对象?作用分别是什么?

答:JSP有9个内置对象:

  • request:封装客户端的请求,其中包含来自GET或POST请求的参数;
  • response:封装服务器对客户端的响应;
  • pageContext:通过该对象可以获取其他对象;
  • session:封装用户会话的对象;
  • application:封装服务器运行环境的对象;
  • out:输出服务器响应的输出流对象;
  • config:Web应用的配置对象;
  • page:JSP页面本身(相当于Java程序中的this);
  • exception:封装页面抛出异常的对象。

补充:如果用Servlet来生成网页中的动态内容无疑是非常繁琐的工作,另一方面,所有的文本和HTML标签都是硬编码,即使做出微小的修改,都需要进行重新编译。JSP解决了Servlet的这些问题,它是Servlet很好的补充,可以专门用作为用户呈现视图(View),而Servlet作为控制器(Controller)专门负责处理用户请求并转发或重定向到某个页面。基于Java的Web开发很多都同时使用了Servlet和JSP。JSP页面其实是一个Servlet,能够运行Servlet的服务器(Servlet容器)通常也是JSP容器,可以提供JSP页面的运行环境,Tomcat就是一个Servlet/JSP容器。第一次请求一个JSP页面时,Servlet/JSP容器首先将JSP页面转换成一个JSP页面的实现类,这是一个实现了JspPage接口或其子接口HttpJspPage的Java类。JspPage接口是Servlet的子接口,因此每个JSP页面都是一个Servlet。转换成功后,容器会编译Servlet类,之后容器加载和实例化Java字节码,并执行它通常对Servlet所做的生命周期操作。对同一个JSP页面的后续请求,容器会查看这个JSP页面是否被修改过,如果修改过就会重新转换并重新编译并执行。如果没有则执行内存中已经存在的Servlet实例。我们可以看一段JSP代码对应的Java程序就知道一切了,而且9个内置对象的神秘面纱也会被揭开。

JSP页面:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<%@ page pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + path + "/";
%>

<!DOCTYPE html>
<html>
<head>
<base href="<%=basePath%>">
<title>首页</title>
<style type="text/css">
* { font-family: "Arial"; }
</style>
</head>

<body>
<h1>Hello, World!</h1>
<hr/>
<h2>Current time is: <%= new java.util.Date().toString() %></h2>
</body>
</html>
阅读全文 »

面向对象的特征有哪些方面?

答:面向对象的特征主要有以下几个方面:

  • 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为,并不关注这些行为的细节是什么。
  • 继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段(如果不能理解请阅读阎宏博士的《Java与模式》或《设计模式精解》中关于桥梁模式的部分)。
  • 封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口(可以想想普通洗衣机和全自动洗衣机的差别,明显全自动洗衣机封装更好因此操作起来更简单;我们现在使用的智能手机也是封装得足够好的,因为几个按键就搞定了所有的事情)。
  • 多态性:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性可以解释为:当A系统访问B系统提供的服务时,B系统有多种提供服务的方式,但一切对A系统来说都是透明的(就像电动剃须刀是A系统,它的供电系统是B系统,B系统可以使用电池供电或者用交流电,甚至还有可能是太阳能,A系统只会通过B类对象调用供电的方法,但并不知道供电系统的底层实现是什么,究竟通过何种方式获得了动力)。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:
    • 方法重写(子类继承父类并重写父类中已有的或抽象的方法)
    • 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。

      访问修饰符public,private,protected,以及不写(默认)时的区别?

      答:区别如下:
作用域 当前类 同包 子类 其他
public
protected ×
default × ×
private × × ×
类的成员不写访问修饰时默认为default。默认对于同一个包中的其他类相当于公开(public),对于不是同一个包中的其他类相当于私有(private)。受保护(protected)对子类相当于公开,对不是同一包中的没有父子关系的类相当于私有。

String 是最基本的数据类型吗?

答:不是。Java中的基本数据类型只有8个:byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type)和枚举类型(enumeration type),剩下的都是引用类型(reference type)。

float f=3.4;是否正确?

答:不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成float f =3.4F;。

short s1 = 1; s1 = s1 + 1;有错吗?short s1 = 1; s1 += 1;有错吗?

答:对于short s1 = 1; s1 = s1 + 1;由于1是int类型,因此s1+1运算结果也是int 型,需要强制转换类型才能赋值给short型。而short s1 = 1; s1 += 1;可以正确编译,因为s1+= 1;相当于s1 = (short)(s1 + 1);其中有隐含的强制类型转换。

阅读全文 »

装配bean

它提供了三种主要的装配机制:

  • 隐式的Bean发现机制和自动装配
  • 在Java中进行显式配置
  • 在XML中进行显式配置

自动化装配Bean

  • 组件扫描(Component Scanning):Spring会自动发现应用上下文中所创建的Bean
  • 自动装配(Autowired):Spring自动满足Bean之间的依赖

@Component

这个注解表明该类会作为组件类(还有个类似的注解--@Named(“bean name”),用法一样。)

@ComponentScan

不过,组件扫描默认是不开启的,用@ComponentScan注解,如果没有其他配置,它默认会扫描与配置类相同的包(包括这个包下的所有子包),查找带有@Component注解的类,并在Spring中自动为其创建一个Bean

@ComponentScan的属性

  • basePackages,值为扫描对象包,如:@ComponentScan(basePackages={“first”,”second”…})
  • basePackageClasses,值为扫描对象类,如:@ComponentScan(basePackageClasses={“first”,”second”…})

@Autowired(@Inject用法大致一样)

自动装配,bean之间的依赖,有构造器、setter方法、其他方法注入。

在构造器上加此注解,如下,表明当Spring创建BeanA的bean时,会通过这个构造器来进行实例化并且会传入一个可设置给BeanB类型的bean
1
2
3
4
5
6
7
8
9
@Component
public BeanA implement BeanDady{
private BeanB b;
@Autowired
public BeanA(BeanB b){
this.b = b
}
}
<!--more-->
用在属性的setter方法上,比如:
1
2
3
4
5
6
7
8
@Component
public BeanA implement BeanDady{
private BeanB b;
@Autowired
public void setBeanB(BeanB b){
this.b = b
}
}
用在方法上,比如:
1
2
3
4
5
6
7
8
@Component
public BeanA implement BeanDady{
private BeanB b;
@Autowired
public void test(BeanB b){
this.b = b
}
}

不管什么方式,Spring都会尝试满足方法参数上所声明的依赖。假如有且只有一个bean匹配依赖需求的话,那么这个bean将会被装配起来,其他情况的话,在应用上下文创建时,Spring会抛出异常。为了避免异常,你可以将@Autowired的属性required设置为false

1
@Autowired(required=false)

设置false后,如果没有匹配的bean,Spring会设置这个bean为未装配的状态,当然你的代码也有可能会出现空指针异常。

通过Java代码装配bean

@Configuration

该注解表明这个类是一个配置类

Bean

声明bean,我们给配置类里的方法加上此注解

1
2
3
4
5
6
7
@Configuratione
public class BeanConfig{
@Bean
public BeanA beanA(){
return new BeanA();
}
}

@Bean注解会告诉Spring这个方法将会返回一个对象,该对象要注册为Spring应用上下文的bean。默认情况下,bean的id跟此方法名一样,你也可以设置@Bean的属性name来指定一个不同的名字

1
@Bean(name="xxx")

通过XML装配bean

不喜欢这种,,,

声明一个简单的bean

1
<bean id="beanA" class="com.BeanA"/>

小结

建议使用自动化配置,减少维护成本。

阅读全文 »

Linux的基本命令入门

目录切换命令

目录结构

  • / (根目录)
    • bin(binaries)存放二进制可执行文件
    • boot 存放用于系统引导时使用的各种文件
    • dev (devices)用于存放设备文件
    • etc (etcetera)存放系统配置文件
    • home 存放用户文件的根目录
      • 每个用户的根目录的存放的位置,home下创建每个用户的根目录。
      • 例如:用户是test,那么在home下就会存在一个叫test的目录
    • lib (library)存放跟文件系统中的程序运行所需要的共享库及内核模块
    • sbin (super user binaries)存放二进制可执行文件,只有root才能访问
    • usr (unix shared resources)用于存放共享的系统资源
    • var (variable)用于存放运行时需要改变数据的文件
    • 目录切换命令

      cd usr 切换到该目录下usr目录
      cd ../ 切换到上一层目录
      cd / 切换到系统根目录
      cd ~ 切换到用户主目录
      cd - 切换到上一个所在目录
      阅读全文 »