裸泳的猪

沾沾自喜其实最可悲

0%

1.spring是什么

Spring 是于 2003 年兴起的一个轻量级的 Java 开发框架,它是为了解决企业应用开发
的复杂性而创建的。Spring 的核心是控制反转(IoC)和面向切面编程(AOP)。


2.IOC控制反转

控制反转(IoC,Inversion of Control),是一个概念,是一种思想。指将传统上由程序代
码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理。控制反转就是对对
象控制权的转移,从程序代码本身反转到了外部容器。通过容器实现对象的创建,属性赋值,
依赖的管理。

spring对于IOC思想的具体实现就是:DI(依赖注入:DI(Dependency Injection),程序代码不做定位查询,这些工作由容器自行完成。)

DI具体用法和实现

ApplicationContext 接口(容器)

ApplicationContext 用于加载 Spring 的配置文件,在程序中充当“容器”的角色。其实现
类有:ClassPathXmlApplicationContext(常用),FileSystemXmlApplicationContext。

  • 若 Spring 配置文件存放在项目的类路径下,则使用 ClassPathXmlApplicationContext 实现
    类进行加载。
  • ApplicationContext 容器,会在容器对象初始化时,将其中的所有对象一次性全部装配好。
    以后代码中若要使用到这些对象,只需从内存中直接获取即可。执行效率较高。但占用内存。
阅读全文 »

1.Lambda 表达式

Lambda 允许把函数作为一个方法的参数(函数作为参数传递到方法中)。

1.1 语法

lambda 表达式的语法格式如下:

(parameters) -> expression或(parameters) ->{statements; }

2.Java 8 方法引用

方法引用提供了非常有用的语法,可以直接引用已有Java类或对象(实例)的方法或构造器。与lambda联合使用,方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

方法引用可以使语言的构造更紧凑简洁,减少冗余代码。

方法引用使用一对冒号 :: 。

1
2
3
4
5
6
7
List names = new ArrayList();
names.add("Google");
names.add("Runoob");
names.add("Taobao");
names.add("Baidu");
names.add("Sina");
names.forEach(System.out::println);

3.默认方法

默认方法就是一个在接口里面有了一个实现的方法。

1
2
3
4
5
public interface vehicle {
default void print() {
System.out.println("我是一辆车!");
}
}

4.新工具

新的编译工具,如:Nashorn引擎 jjs、 类依赖分析器jdeps。

5.Stream API

5.1概念理解

新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中。

Java 8 API添加了一个新的抽象称为流Stream,可以让你以一种声明的方式处理数据。

Stream使用一种类似用SQL语句从数据库查询数据的直观方式来提供一种对Java集合运算和表达的高阶抽象。

Stream API可以极大提高Java程序员的生产力,让程序员写出高效率、干净、简洁的代码。

这种风格将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如筛选,排序,聚合等。

元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。

5.2生成流

在Java 8中,集合接口有两个方法来生成流:

stream() −为集合创建串行流。

parallelStream() − 为集合创建并行流。

1
public` `static` `void` `main(String[] args) {``  ``List<String> strings = Arrays.asList(``"abc"``, ``""``, ``"bc"``, ``"efg"``, ``"abcd"``, ``""``, ``"jkl"``);``  ``List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());``}

  

5.3 forEach

Stream 提供了新的方法 ‘forEach’ 来迭代流中的每个数据。以下代码片段使用forEach 输出了10个随机数:

1
Random random = ``new` `Random();``random.ints().limit(``10``).forEach(System.out::println);

  

5.4 map

map 方法用于映射每个元素到对应的结果,以下代码片段使用 map 输出了元素对应的平方数:

1
List<Integer> numbers = Arrays.asList(``3``, ``2``, ``2``, ``3``, ``7``, ``3``, ``5``);``// 获取对应的平方数``List<Integer> squaresList = numbers.stream().map(i -> i * i).distinct().collect(Collectors.toList());

  

5.5 filter

filter 方法用于通过设置条件过滤出元素。以下代码片段使用filter 方法过滤出空字符串:

1
List<String>strings = Arrays.asList(``"abc"``, ``""``, ``"bc"``, ``"efg"``, ``"abcd"``,``""``, ``"jkl"``);``// 获取空字符串的数量``int` `count = (``int``) strings.stream().filter(string -> string.isEmpty()).count();

  

5.6 limit

limit 方法用于获取指定数量的流。以下代码片段使用 limit 方法打印出 10 条数据:

1
Random random = ``new` `Random();``random.ints().limit(``10``).forEach(System.out::println);

  

5.7 sorted

sorted 方法用于对流进行排序。以下代码片段使用 sorted 方法对输出的 10 个随机数进行排序:

1
Random random = ``new` `Random();``random.ints().limit(``10``).sorted().forEach(System.out::println);

  

5.8 并行(parallel)程序

parallelStream 是流并行处理程序的代替方法。以下实例我们使用parallelStream 来输出空字符串的数量:

1
List<String> strings = Arrays.asList(``"abc"``, ``""``, ``"bc"``, ``"efg"``, ``"abcd"``, ``""``, ``"jkl"``);``// 获取空字符串的数量``int` `count = (``int``) strings.parallelStream().filter(string -> string.isEmpty()).count();

  

我们可以很容易的在顺序运行和并行直接切换。

5.9 Collectors

Collectors 类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors可用于返回列表或字符串:

1
List<String> strings = Arrays.asList(``"abc"``, ``""``, ``"bc"``, ``"efg"``, ``"abcd"``, ``""``, ``"jkl"``);``List<String> filtered = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.toList());``System.out.println(``"筛选列表: "` `+ filtered);``String mergedString = strings.stream().filter(string -> !string.isEmpty()).collect(Collectors.joining(``", "``));``System.out.println(``"合并字符串: "` `+ mergedString);

  

5.10 统计

另外,一些产生统计结果的收集器也非常有用。它们主要用于int、double、long等基本类型上,它们可以用来产生类似如下的统计结果。

1
List<Integer> numbers = Arrays.asList(``3``, ``2``, ``2``, ``3``, ``7``, ``3``, ``5``);``IntSummaryStatistics stats = numbers.stream().mapToInt((x) -> x).summaryStatistics();``System.out.println(``"列表中最大的数 : "` `+ stats.getMax());``System.out.println(``"列表中最小的数 : "` `+ stats.getMin());``System.out.println(``"所有数之和 : "` `+ stats.getSum());``System.out.println(``"平均数 : "` `+ stats.getAverage());

6.Date Time API

加强对日期与时间的处理。

7.Optional 类

Optional 类是一个可以为null的容器对象。如果值存在则isPresent()方法会返回true,调用get()方法会返回该对象。

Optional 是个容器:它可以保存类型T的值,或者仅仅保存null。Optional提供很多有用的方法,这样我们就不用显式进行空值检测。

Optional 类的引入很好的解决空指针异常。

1
2
3
4
5
6
Integer value1 = null;
Integer value2 = new Integer(10);
// Optional.ofNullable - 允许传递为 null 参数
Optional<Integer> a = Optional.ofNullable(value1);
// Optional.of - 如果传递的参数是 null,抛出异常 NullPointerException
Optional<Integer> b = Optional.of(value2);

8.Nashorn JavaScript 引擎

Java 8提供了一个新的Nashorn javascript引擎,它允许我们在JVM上运行特定的javascript应用。

参考:java8新特性详解及示例代码

Zookeeper基础概念

ZooKeeper是一个开放源码的分布式协调服务,它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供给用户。

分布式应用程序可以基于Zookeeper实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能。

客户端的读请求可以被集群中的任意一台机器处理,如果读请求在节点上注册了监听器,这个监听器也是由所连接的zookeeper机器来处理。对于写请求,这些请求会同时发给其他zookeeper机器并且达成一致后,请求才会返回成功。因此,随着zookeeper的集群机器增多,读请求的吞吐会提高但是写请求的吞吐会下降。

有序性是zookeeper中非常重要的一个特性,所有的更新都是全局有序的,每个更新都有一个唯一的时间戳,这个时间戳称为zxid(Zookeeper Transaction Id)。而读请求只会相对于更新有序,也就是读请求的返回结果中会带有这个zookeeper最新的zxid。

ZooKeeper提供了什么?

区别于Eureka专用于注册中心的功能,zookeeper主要提供的能力是

  • 文件系统
  • 通知机制

Zookeeper文件系统

  • Zookeeper提供一个多层级的节点命名空间(节点称为znode)。与文件系统不同的是,这些节点都可以设置关联的数据,而文件系统中只有文件节点可以存放数据而目录节点不行。
  • Zookeeper为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,这种特性使得Zookeeper不能用于存放大量的数据,每个节点的存放数据上限为1M

ZAB协议?

ZAB协议是为分布式协调服务Zookeeper专门设计的一种支持崩溃恢复的原子广播协议。

ZAB协议包括两种基本的模式:崩溃恢复和消息广播

当整个zookeeper集群刚刚启动或者Leader服务器宕机、重启或者网络故障导致不存在过半的服务器与Leader服务器保持正常通信时,所有进程(服务器)进入崩溃恢复模式,首先选举产生新的Leader服务器,然后集群中Follower服务器开始与新的Leader服务器进行数据同步,当集群中超过半数机器与该Leader服务器完成数据同步之后,退出恢复模式进入消息广播模式,Leader服务器开始接收客户端的事务请求生成事物提案来进行事务请求处理。

四种类型的数据节点 Znode

  • PERSISTENT-持久节点
    除非手动删除,否则节点一直存在于Zookeeper上
  • EPHEMERAL-临时节点
    临时节点的生命周期与客户端会话绑定,一旦客户端会话失效(客户端与zookeeper连接断开不一定会话失效),那么这个客户端创建的所有临时节点都会被移除。
  • PERSISTENT_SEQUENTIAL-持久顺序节点
    基本特性同持久节点,只是增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。
  • EPHEMERAL_SEQUENTIAL-临时顺序节点
    基本特性同临时节点,增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。

Zookeeper Watcher 机制 – 数据变更通知

Zookeeper允许客户端向服务端的某个Znode注册一个Watcher监听,当服务端的一些指定事件触发了这个Watcher,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据Watcher通知状态和事件类型做出业务上的改变。

工作机制:

  • 客户端注册watcher
  • 服务端处理watcher
  • 客户端回调watcher

Watcher特性总结:

  1. 一次性
    无论是服务端还是客户端,一旦一个Watcher被触发,Zookeeper都会将其从相应的存储中移除。这样的设计有效的减轻了服务端的压力,不然对于更新非常频繁的节点,服务端会不断的向客户端发送事件通知,无论对于网络还是服务端的压力都非常大。
  2. 客户端串行执行
    客户端Watcher回调的过程是一个串行同步的过程。
  3. 轻量
    • Watcher通知非常简单,只会告诉客户端发生了事件,而不会说明事件的具体内容。
    • 客户端向服务端注册Watcher的时候,并不会把客户端真实的Watcher对象实体传递到服务端,仅仅是在客户端请求中使用boolean类型属性进行了标记。
  4. watcher event异步发送watcher的通知事件从server发送到client是异步的,这就存在一个问题,不同的客户端和服务器之间通过socket进行通信,由于网络延迟或其他因素导致客户端在不通的时刻监听到事件,由于Zookeeper本身提供了ordering guarantee,即客户端监听事件后,才会感知它所监视znode发生了变化。所以我们使用Zookeeper不能期望能够监控到节点每次的变化。Zookeeper只能保证最终的一致性,而无法保证强一致性。
  5. 注册watcher getData、exists、getChildren
  6. 触发watcher create、delete、setData
  7. 当一个客户端连接到一个新的服务器上时,watch将会被以任意会话事件触发。当与一个服务器失去连接的时候,是无法接收到watch的。而当client重新连接时,如果需要的话,所有先前注册过的watch,都会被重新注册。通常这是完全透明的。只有在一个特殊情况下,watch可能会丢失:对于一个未创建的znode的exist watch,如果在客户端断开连接期间被创建了,并且随后在客户端连接上之前又删除了,这种情况下,这个watch事件可能会被丢失。

ZooKeeper实现分布式锁原理

其实如果有客户端C、客户端D等N个客户端争抢一个zk分布式锁,原理都是类似的。

  • 大家都是上来直接创建一个锁节点下的一个接一个的临时顺序节点
  • 如果自己不是第一个节点,就对自己上一个节点加监听器
  • 只要上一个节点释放锁,自己就排到前面去了,相当于是一个排队机制。

而且用临时顺序节点的另外一个用意就是,如果某个客户端创建临时顺序节点之后,不小心自己宕机了也没关系,zk感知到那个客户端宕机,会自动删除对应的临时顺序节点,相当于自动释放锁,或者是自动取消自己的排队。

线程创建方式

  1. 继承Thread类
    • start()方法是一个 native 方法,它将启动一个新线程,并执行 run()方法。
  2. 实现runnable接口,
    • 当一个类已经有继承了,此时可通过实现runnable接口来创建线程
  3. 采用线程池,实现callable接口(有返回),ExecutorService
    • 有返回值的任务必须实现 Callable 接口。执行Callable 任务后,可以获取一个Future 的对象,在该对象上调用 get 就可以获取到 Callable 任务返回的 Object 了,再结合线程池接口 ExecutorService 就可以实现传说中有返回结果的多线程了。

多线程中的主要问题

  1. 可见性问题
    volatile修饰,保证了多线程之间的内存可见性
  2. 原子性问题
    AtomicInteger(Java中有那么一些类,是以Atomic开头的。这一系列的类我们称之为原子操作类。以最简单的类AtomicInteger为例。它相当于一个int变量,我们执行Int的 i++ 的时候并不是一个原子操作。而使用AtomicInteger的incrementAndGet却能保证原子操作)
  3. 有序性问题
    volatile 防止指令重排序
  4. 死锁的问题

synchronized 关键字

用法:

  1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;

  2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;

  3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个==类的所有对象==;

  4. 修改一个,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

阅读全文 »

什么是MVC

  • M代表模型(Model)
    模型其实就是数据,dao,bean
  • V代表视图(View)
    网页,jsp等用来展示数据的模型
  • C代表Controller
    把不同的数据展示在不同的视图上,处理请求的分发,Servlet扮演的就是这样的角色
    MVC

SpringMVC的流程

  1. 用户发送请求至前端控制器DispatcherServlet;

  2. DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handler;

  3. 处理器映射器根据请求url找到具体的处理器Handler,生成处理器对象及处理器拦截器(如果有则生成),一并返回给DispatcherServlet;

  4. DispatcherServlet 调用 HandlerAdapter处理器适配器,请求执行Handler;

  5. HandlerAdapter 经过适配调用 具体处理器进行处理业务逻辑;

  6. Handler执行完成返回ModelAndView;

  7. HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;

  8. DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;

  9. ViewResolver解析后返回具体View;

  10. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)

  11. DispatcherServlet响应用户。

阅读全文 »

SpringCloud进阶

  • javase
  • 数据库
  • [] 前端
  • [] servlet
  • [] Http
  • Mybatis
  • Spring
  • [] SpringMVC
  • [] SpringBoot
  • Dubbo,zookeeper,分布式基础
  • maven

总结一下SpringCloud结果核心组件:

  • Eureka:个服务启动时,Eureka会将服务注册到EurekaService,并且EurakeClient还可以返回过来从EurekaService拉去注册表,从而知道服务在哪里

  • Ribbon:服务间发起请求的时候,基于Ribbon服务做到负载均衡,从一个服务的对台机器中选择一台

    目前,在Spring cloud 中服务之间通过restful方式调用有两种方式

    • restTemplate+Ribbon
    • feign
  • Feign:RPC框架,基于fegin的动态代理机制,根据注解和选择机器,拼接Url地址,发起请求,Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。

  • Hystrix:发起的请求是通过Hystrix的线程池来走,不同的服务走不同的线程池,实现了不同的服务调度隔离,避免服务雪崩的问题

  • Zuul:如果前端后端移动端调用后台系统,统一走zull网关进入,有zull网关转发请求给对应的服务

  • Apollo(阿波罗)是携程框架部门研发的配置管理平台,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性。Apollo配置中心设计

Ribbon

Ribbon 是一个基于 HTTP 和 TCP 客户端的负载均衡器

它可以在客户端配置 ribbonServerList(服务端列表),然后轮询请求以实现均衡负载

它在联合 Eureka 使用时

ribbonServerList 会被 DiscoveryEnabledNIWSServerList 重写,扩展成从 Eureka 注册中心获取服务端列表

同时它也会用 NIWSDiscoveryPing 来取代 IPing,它将职责委托给 Eureka 来确定服务端是否已经启动

Feign

Spring Cloud Netflix 的微服务都是以 HTTP 接口的形式暴露的,所以可以用 Apache 的 HttpClient 或 Spring 的 RestTemplate 去調用,而 Feign 是一個使用起來更加方便的 HTTP 客戶端,它用起來就好像調用本地方法一樣,完全感覺不到是調用的遠程方法

总结起来就是:发布到注册中心的服务方接口,是 HTTP 的,也可以不用 Ribbon 或者 Feign,直接浏览器一样能够访问

只不过 Ribbon 或者 Feign 调用起来要方便一些,最重要的是:它俩都支持软负载均衡

注意:spring-cloud-starter-feign 里面已经包含了 spring-cloud-starter-ribbon(Feign 中也使用了 Ribbon)

从实践上看,采用feign的方式更优雅(feign内部也使用了ribbon做负载均衡)。

Spring Cloud 和dubbo区别?

其实Dubbo仅仅是一个RPC框架,实现Java程序的远程调用,而Spring Cloud则是实施微服务的一系列套件,包括:服务注册与发现、断路器、服务状态监控、配置管理、智能路由、一次性令牌、全局锁、分布式会话管理、集群状态管理等

(1)服务调用方式 dubbo是RPC,springcloud是 Rest Api

(2)注册中心,dubbo 是zookeeper springcloud是eureka,也可以是zookeeper

(3)服务网关,dubbo本身没有实现,只能通过其他第三方技术整合,springcloud有Zuul路由网关,作为路由服务器,进行消费者的请求分发,springcloud支持断路器,与git完美集成配置文件支持版本控制,事物总线实现配置文件的更新与服务自动装配等等一系列的微服务架构要素。

常见的RPC组件:

  1. RMI(远程方法调用)

JAVA自带的远程方法调用工具,不过有一定的局限性,毕竟是JAVA语言最开始时的设计,后来很多框架的原理都基于RMI。

  1. Hessian(基于HTTP的远程方法调用)

    基于HTTP协议传输,在性能方面还不够完美,负载均衡和失效转移依赖于应用的负载均衡器,Hessian的使用则与RMI类似,区别在于淡化了Registry的角色,通过显示的地址调用,利用HessianProxyFactory根据配置的地址create一个代理对象,另外还要引入Hessian的Jar包。

  2. Dubbo(淘宝开源的基于TCP的RPC框架)

基于Netty的高性能RPC框架,是阿里巴巴开源的,总体原理如下:

SpringBoot主要特性

Spring boot 简化了使用 Spring 的难度,简省了繁重的配置(版本管理,依赖导入),提供了各种启动器,开发者能快速上手。

SpringBoot的版本控制

pom.xml中有父项目

  • spring-boot-dependencies:核心依赖在父工程中

  • 我们在写或者应用引入一些springboot的依赖的时候,不需要指定版本,因为有相关版本库。

SpringBoot的自动装配

SpringBoot 自动配置主要通过 @EnableAutoConfiguration, @Conditional, @EnableConfigurationProperties 或者 @ConfigurationProperties 等几个注解来进行自动配置完成的。

  • @EnableAutoConfiguration 开启自动配置,主要作用就是调用 Spring-Core 包里的 loadFactoryNames(),将 autoconfig 包里的已经写好的自动配置加载进来。

  • @Conditional 条件注解,通过判断类路径下有没有相应配置的 jar 包来确定是否加载和自动配置这个类。

  • @EnableConfigurationProperties 的作用就是,给自动配置提供具体的配置参数,只需要写在 application.properties 中,就可以通过映射写入配置类的 POJO 属性中。

    springboot_start

    该配置模块的主要使用到了SpringFactoriesLoader,即Spring工厂加载器,该对象提供了loadFactoryNames()方法,入参为factoryClass和classLoader,即需要传入上图中的工厂类名称和对应的类加载器,方法会根据指定的classLoader,加载该类加器搜索路径下的指定文件,即指定的配置文件META-INF/spring.factories,传入的工厂类为接口,而文件中对应的类则是接口的实现类,或最终作为实现类,所以文件中一般为一对多的类名集合,获取到这些实现类的类名后,loadFactoryNames方法返回类名集合,方法调用方得到这些集合后,再通过反射获取这些类的类对象、构造方法,最终生成实例。

    springboot_EnableAutoConfiguration

什么是 Spring Boot Stater ?

启动器是一套方便的依赖描述符,它可以放在自己的程序中。你可以一站式的获取你所需要的 Spring 和相关技术,而不需要依赖描述符的通过示例代码搜索和复制黏贴的负载。

阅读全文 »