Spring
概念
spring是个java企业级应用的开源框架。spring主要用来开发java应用,但是有些扩展是针对J2EE平台的文本应用。Spring框架目标是简化java企业级应用的开发,并通过pojo为基础的编程模型促进良好的编程习惯。
优点
- 轻量:spring是轻量的,基本的版本大约2MB;
- 控制反转:spring通过控制反转实现了松散耦合,对象们给出他们的依赖,而不是创建或查找依赖的对象们;
- 面向切面编程(AOP):spring支持面向切面的编程,并且应用业务逻辑和系统服务分开;
- 容器:spring包含并管理应用中对象的生命周期和配置;
- MVC框架:spring的web框架是个精心设计的框架,是web框架的一个很好的替代品;
- 事务管理:spring提供一个特殊的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA);
- 异常处理:spring提供方便的API把具体技术相关的异常(列如JDBC)转化为一致的unchecked异常;
spring中使用的设计模式
- 简单工厂模式:又叫静态工厂方法模式,spring中的BeanFactory就是一个简单工厂模式的体现,根据传入一个唯一的标识来获得bean对象;
- 工厂方法模式:通常有应用程序直接使用new创建新的对象,为了将对象的创建和使用分离,采用工厂模式,即应用程序将对象的创建及初始化职责交给工厂对象。一般情况下,应用程序有自己的工厂对象类创建bean,如果将应用程序自己的工厂对象交给spring管理,那么spring管理的就不是bean,而是工厂bean;
- 单列模式:保证一个类仅有一个实例,并提供一个访问他的全局访问点。在spring中提供了全局的访问点BeanFactory,但没有从构造器级别去控制单列,这是因为spring管理的是任意的java对象;
- 适配器模式:在spring中的AOP中,使用Advice(通知)来增强被代理类的功能。spring实现这一AOP功能的原理就是代理模式(jdk动态代理和CGLib代理)对类进行方法级别的切面增强,来实现的面向切面编程;
- 包装器模式:spring中用到的包装器模式在类名上有两种表现:一种是类名中含有Wrapper,另一种是类名含有Decorator。(多数据源的切换列子);
- 代理模式:为其他对象提供一种代理以控制对这个对象的访问(spring的Proxy模式在AOP中有体现);
- 观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于他的对象都得到通知并自动更新;(spring中Observer模式常用的地方是listener的实现);
- 策略模式:定义一系列的算法,把他们一个个封装起来,并且使他们可互相替换。(spring中在实例化对象的时候用到Strategy模式);
- 模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中(spring中的JdbcTemplate的使用);
Spring AOP
AOP(可以说是对oop的补充和完善)它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
关键点:
- 横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点;
- 切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象;
- 连接点(joinpoint):被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器;
- 切入点(pointcut):对连接点进行拦截的定义;
- 通知(advice):所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类目标对象;
- 目标对象:代理的目标对象;
- 织入(weave):将切面应用到目标对象并导致代理对象创建的过程;
- 引入(introduction):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。
Spring IOC
IOC(控制反转)意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
IOC 不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。
- 谁控制谁?当然是IoC容器控制了对象;
- 控制什么?那就是主要控制了外部资源获取(不只是对象包括比如文件等)。
- 为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;
- 哪些方面反转了?依赖对象的获取被反转了。
依赖注入方式
- 构造器依赖注入:构造器依赖注入通过容器触发一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。
- Setter方法注入:Setter方法注入是容器通过调用无参构造器或无参static工厂方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入。
Spring DI
DI(依赖注入)组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现。
- 谁依赖于谁:当然是应用程序依赖于IoC容器;
- 为什么需要依赖:应用程序需要IoC容器来提供对象需要的外部资源;
- 谁注入谁:很明显是IoC容器注入应用程序某个对象,应用程序依赖的对象;
- 注入了什么:就是注入某个对象所需要的外部资源(包括对象、资源、常量数据)。
IoC和DI由什么关系呢?其实它们是同一个概念的不同角度描述,由于控制反转概念比较含糊(可能只是理解为容器控制对象这一个层面,很难让人想到谁来维护对象关系),所以2004年大师级人物Martin Fowler又给出了一个新的名字:“依赖注入”,相对IoC 而言,“依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”。
Spring Bean的作用域
- singleton : bean在每个Spring ioc 容器中只有一个实例(是缺省的Spring bean 作用域)。
- prototype:一个bean的定义可以有多个实例。
- request:每次http请求都会创建一个bean,该作用域仅在基于web的Spring ApplicationContext情形下有效。
- session:在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
- global-session:在一个全局的HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
Spring注入Java集合的方式
- 类型用于注入一列值,允许有相同的值。
- 类型用于注入一组值,不允许有相同的值。
- 类型用于注入一组键值对,键和值都只能为String类型。
Spring Bean的自动装配
- no:默认的方式是不进行自动装配,通过显式设置ref 属性来进行装配。
- byName:通过参数名 自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byname,之后容器试图匹配、装配和该bean的属性具有相同名字的bean。
- byType::通过参数类型自动装配,Spring容器在配置文件中发现bean的autowire属性被设置成byType,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件,则抛出错误。
- constructor:这个方式类似于byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。
- autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。
常用注解
- @Configuration:它用来标记类可以当做一个bean的定义,被Spring IOC容器使用。
- @Bean:它表示此方法将要返回一个对象,作为一个bean注册进Spring应用上下文。
- @Required:这个注解表明bean的属性必须在配置的时候设置,通过一个bean定义的显式的属性值或通过自动装配,若@Required注解的bean属性未被设置,容器将抛出BeanInitializationException。
- @Autowired:提供了更细粒度的控制,包括在何处以及如何完成自动装配。它的用法和@Required一样,修饰setter方法、构造器、属性或者具有任意名称和/或多个参数的PN方法。
- @Qualifier:当有多个相同类型的bean却只有一个需要自动装配时,将@Qualifier 注解和@Autowire 注解结合使用以消除这种混淆,指定需要装配的确切的bean。
- @Autowired和@Resource的区别:@Resource和@Autowired都是做bean的注入时使用,其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。
Spring 的事务管理
Spring支持两种类型的事务管理
- 编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。
- 声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务。
事务管理的优点
- 它为不同的事务API 如 JTA,JDBC,Hibernate,JPA 和JDO,提供一个不变的编程模式;
- 它为编程式事务管理提供了一套简单的API而不是一些复杂的事务API如;
- 它支持声明式事务管理;
- 它和Spring各种数据访问抽象层很好得集成。
Spring MVC
SpringMVC是一个基于MVC架构的用来简化web应用程序开发的应用开发架构,他是spring的一个模块,无需中间整合层来整合,他和Struts2一样都属于表现层的框架。在web模型中,MVC是一种很流行的框架,通过把Model,View,Controller分离,把较为复杂的web应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合。
原理
- 用户发送请求至前端控制器DispatcherServlet;
- DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handle;
- 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet;
- DispatcherServlet通过HandlerAdapter处理器适配器调用处理器;
- 执行处理器(Handler,也叫后端控制器);
- Handler执行完成返回ModelAndView;
- HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet;
- DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;
- ViewResolver解析后返回具体View;
- DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
- DispatcherServlet响应用户。
优点
- 它是基于组件技术的。全部的应用对象,无论控制器和视图,还是业务对象之类的都是 java组件.并且和Spring提供的其他基础结构紧密集成;
- 不依赖于Servlet API(目标虽是如此,但是在实现的时候确实是依赖于Servlet的);
- 可以任意使用各种视图技术,而不仅仅局限于JSP;
- 支持各种请求资源的映射策略;
- 它应是易于扩展的。
相关注解
- @Conntroller: 用于控制层注解,不能用用别的注解代替;
- @RequestMapping: 用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径(method=RequestMethod.GET)。
- @ResponseBody: 将内容或对象作为 HTTP 响应正文返回,并调用适合HttpMessageConverter的Adapter转换对象,写入输出流;
- @RequestBody:将HTTP请求正文转换为适合的HttpMessageConverter对象;
- @SessionAttributes:用来在controller内部共享model属性的;
- @RequestParam:绑定单个请求参数值;
- @PathVariable:绑定URI模板变量值;
- @ModelAttribute:可以应用在方法参数上或方法上,他的作用主要是当注解在方法参数上时会将注解的参数对象添加到Model中;当注解在请求处理方法Action上时会将该方法变成一个非请求处理的方法,但其它Action被调用时会首先调用该方法。
- @Component:在类定义之前添加@Component注解,他会被spring容器识别,并转为bean;
- @Repository:对dao实现类进行注解;
- @Service:用于对业务逻辑层进行注解;
SpringBoot
Spring Boot 是 Spring 开源组织下的子项目,是Spring组件一站式解决方案,主要是简化了使用Spring的难度,简省了繁重的配置,提供了各种启动器,开发者能快速上手。
优点
- 独立运行
- 简化配置
- 自动配置
- 无代码生成和JavaConfig有助于避免使用XML
- 应用监控
- 上手容易
核心配置文件
- application:主要用于springboot项目的自动化配置;
- bootstrap:一些固定的不能被覆盖的属性、一些加密或解密的场景。
相关注解
- @SpringBootApplication:启动类上面的注解,是springboot的核心注解;
- @SpringBootConfiguration:组合了 @Configuration 注解,实现配置文件的功能;
- @EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能:@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class });
- @ComponentScan:Spring组件扫描。
JavaConfig
Spring JavaConfig是Spring社区的产品,它提供了配置Spring IoC容器的纯Java方法。因此它有助于避免使用XML配置。
JavaConfig的优点:
- 面向对象的配置
- 减少或消除XML配置
- 类型安全和重构友好
SpringCloud
微服务
微服务是指开发一个单个小型的但有业务功能的服务,每个服务都有自己的处理和轻量通讯机制,可以部署在单个或多个服务器上。微服务也指一种种松耦合的、有一定的有界上下文的面向服务架构。也就是说,如果每个服务都要同时修改,那么它们就不是微服务,因为它们紧耦合在一起;如果你需要掌握一个服务太多的上下文场景使用条件,那么它就是一个有上下文边界的服务,这个定义来自DDD领域驱动设计。
相对于单体架构和SOA,它的主要特点是组件化、松耦合、自治、去中心化,体现在以下几个方面:
- 一组小的服务:服务粒度要小,而每个服务是针对一个单一职责的业务能力的封装,专注做好一件事情。
- 独立部署运行和扩展:每个服务能够独立被部署并运行在一个进程内。这种运行和部署方式能够赋予系统灵活的代码组织方式和发布节奏,使得快速交付和应对变化成为可能。
- 独立开发和演化:技术选型灵活,不受遗留系统技术约束。合适的业务问题选择合适的技术可以独立演化。服务与服务之间采取与语言无关的API进行集成。相对单体架构,微服务架构是更面向业务创新的一种架构模式。
- 独立团队和自治:团队对服务的整个生命周期负责,工作在独立的上下文中,自己决策自己治理,而不需要统一的指挥中心。团队和团队之间通过松散的社区部落进行衔接。
核心组件
- Eureka:服务注册于发现。
- Feign:基于动态代理机制,根据注解和选择的机器,拼接请求 url 地址,发起请求。
- Ribbon:实现负载均衡,从一个服务的多台机器中选择一台。
- Hystrix:提供线程池,不同的服务走不同的线程池,实现了不同服务调用的隔离,避免了服务雪崩的问题。
- Zuul:网关管理,由 Zuul 网关转发请求给对应的服务。
- Config:分布式统一配置管理。
优点
- 与分布式系统相关的复杂性:这种开销包括网络问题,延迟开销,带宽问题,安全问题。
- 服务发现:服务发现工具管理群集中的流程和服务如何查找和互相交谈。它涉及一个服务目录,在该目录中注册服务,然后能够查找并连接到该目录中的服务。
- 冗余:分布式系统中的冗余问题。
- 负载平衡:负载平衡改善跨多个计算资源的工作负荷,诸如计算机,计算机集群,网络链路,中央处理单元,或磁盘驱动器的分布。
- 性能问题:由于各种运营开销导致的性能问题。
- 部署复杂性-Devops技能的要求。
服务注册与发现
服务在发布时指定对应的服务名(服务名包括了IP地址和端口)将服务注册到注册中心(eureka、zookeeper等),这一过程是springcloud自动实现 只需要在main方法添加@EnableDisscoveryClient同一个服务修改端口就可以启动多个实例调用方法:传递服务名称通过注册中心获取所有的可用实例 通过负载均衡策略调用(ribbon和feign)对应的服务。
Ribbon和Feign区别
- 启动类使用的注解不同,Ribbon用的是@RibbonClient,Feign用的是@EnableFeignClients。
- 服务的指定位置不同,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明。
- 调用方式不同,Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务,步骤相当繁琐。
断容器的作用
当一个服务调用另一个服务由于网络原因或者自身原因出现问题时调用者就会等待被调用者的响应当更多的服务请求到这些资源时,导致更多的请求等待这样就会发生连锁效应(雪崩效应)断路器就是解决这一问题。
断路器有三种状态:
- 打开状态:一定时间内达到一定的次数无法调用并且多次检测没有恢复的迹象断路器完全打开,那么下次请求就不会请求到该服务;
- 半开状态:短时间内有恢复迹象断路器会将部分请求发给该服务当能正常调用时断路器关闭;
- 关闭状态:当服务一直处于正常状态能正常调用断路器关闭。
微服务之间独立通信
远程过程调用(Remote Procedure Invocation):也就是我们常说的服务的注册与发现,直接通过远程过程调用来访问别的service。
- 优点:简单,因为没有中间件代理,系统更简单;
- 缺点:只支持请求/响应的模式,不支持别的,比如通知、请求/异步响应、发布/订阅、发布/异步响应;降低了可用性,因为客户端和服务端在请求过程中必须都是可用的。
消息:使用异步消息来做服务间通信,服务间通过消息管道来交换消息,从而通信。
- 优点: 把客户端和服务端解耦,更松耦合;提高可用性,因为消息中间件缓存了消息,直到消费者可以消费;支持很多通信机制比如通知、请求/异步响应、发布/订阅、发布/异步响应。
- 缺点: 消息中间件有额外的复杂。
负载均衡
负载均衡可以改善跨计算机,计算机集群,网络链接,中央处理单元或磁盘驱动器等多种计算资源的工作负载分布。
负载均衡旨在优化资源使用,最大吞吐量,最小响应时间并避免任何单一资源的过载。使用多个组件进行负载均衡而不是单个组件可能会通过冗余来提高可靠性和可用性。
负载平衡通常涉及专用软件或硬件,例如多层交换机或域名系统服务进程。
Dubbo
Dubbo是一个由阿里巴巴开源的、分布式的RPC(Remote Procedure Call Protocol-远程过程调用)和微服务框架,现已成为Apache基金会孵化项目。Dubbo提供了三个关键功能:基于接口的远程调用,容错与负载均衡,服务自动注册与发现。
支持的协议
- dubbo(推荐):Dubbo 缺省协议是dubbo协议,采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。反之,Dubbo 缺省协议不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低;
- rmi:RMI协议采用阻塞式(同步)短连接和 JDK 标准序列化方式。适用范围:传入传出参数数据包大小混合,消费者与提供者个数差不多,可传文件;
- hessian:Hessian底层采用Http通讯(同步),采用Servlet暴露服务,Dubbo 缺省内嵌 Jetty 作为服务器实现。适用于传入传出参数数据包较大,提供者比消费者个数多,提供者压力较大,可传文件;
- http:基于 HTTP 表单的远程调用协议,采用 Spring 的 HttpInvoker 实现;
- webservice:基于 WebService 的远程调用协议,基于 ApacheCXF的 frontend-simple 和 transports-http 实现;
- thrift:当前dubbo支持的thrift协议是对thrift原生协议的扩展,在原生协议的基础上添加了一些额外的头信息,比如 service name,magic number 等。使用 dubbo thrift 协议同样需要使用 thrift 的 idl compiler 编译生成相应的 java 代码,后续版本中会在这方面做一些增强;
- memcached:基于 memcached实现的RPC协议 ;
- redis:基于Redis实现的RPC协议。
Dubbo允许配置多协议,在不同服务上支持不同协议或者同一服务上同时支持多种协议。不同服务在性能上适用不同协议进行传输,比如大数据用短连接协议,小数据大并发用长连接协议。
Dubbo和SpringCloud的区别
两个没关联,如果硬要说区别,有以下两点:
- 通信方式不同:Dubbo使用的是RPC通信,而SpringCloud使用的是HTTP RESTFul方式。
- 组成部分不同:dubbo使用zookeeper作为注册中心,而springcloud使用pringcloud Netflix Eureka,dubbo使用Dubbo-monitor作为服务监控的,而springcloud使用springboot Admin作为服务的监控,springcloud还有网关、配置中心、服务跟踪、消息总线、数据流、批量任务等组件,dubbo是没有的。
在Provider上可以配置的Consumer端的属性有哪些
- timeout:方法调用超时;
- retries:失败重试次数,默认重试 2 次;
- loadbalance:负载均衡算法,默认随机;
- actives:消费者端,最大并发调用限制.
Dubbo推荐使用什么序列化框架
推荐使用Hessian序列化,还有Duddo、FastJson、Java自带序列化。
通信框架
Dubbo默认使用Netty框架,也是推荐的选择,另外内容还集成有Mina、Grizzly。
Dubbo服务之间的调用
默认是同步等待结果阻塞的,支持异步调用。
Dubbo是基于NIO的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小,异步调用会返回一个Future对象。
如何优雅停机
Dubbo是通过JDK的ShutdownHook来完成优雅停机的,所以如果使用kill -9 PID等强制关闭指令,是不会执行优雅停机的,只有通过kill PID时,才会执行。
服务读写推荐的容错策略
- 读操作建议使用Failover失败自动切换,默认重试两次其他服务器。
- 写操作建议使用Failfast快速失败,发一次调用失败就立即报错。
服务暴露的过程
Dubbo会在Spring实例化完bean之后,在刷新容器最后一步发布ContextRefreshEvent事件的时候,通知实现了ApplicationListener的ServiceBean类进行回调onApplicationEvent事件方法,Dubbo会在这个方法中调用ServiceBean父类ServiceConfig的export方法,而该方法真正实现了服务的(异步或者非异步)发布。
服务注册
以zookeeper为例
- 服务提供者启动时: 向 /dubbo/com.foo.BarService/providers目录下写入自己的URL地址;
- 服务消费者启动时: 订阅 /dubbo/com.foo.BarService/providers目录下的提供者URL地址。并向 /dubbo/com.foo.BarService/consumers目录下写入自己的URL地址;
- 监控中心启动时: 订阅 /dubbo/com.foo.BarService目录下的所有提供者和消费者URL地址。
支持以下功能:
- 当提供者出现断电等异常停机时,注册中心能自动删除提供者信息
- 当注册中心重启时,能自动恢复注册数据,以及订阅请求
- 当会话过期时,能自动恢复注册数据,以及订阅请求
- 当设置 时,记录失败注册和订阅请求,后台定时重试
- 可通过 设置 zookeeper 登录信息
- 可通过 设置 zookeeper 的根节点,不设置将使用无根树
- 支持 * 号通配符 ,可订阅服务的所有分组和所有版本的提供者
集群容错方案
- Failover Cluster(默认):失败自动切换,自动重试其他服务器;
- Failfast Cluster:快速失败,立即报错,只发起一次调用;
- Failsafe Cluster:失败安全,出现异常时,直接忽略;
- Failback Cluster:失败自动恢复,记录失败请求,定时重发;
- Failking Cluster:并行调用多个服务器,只要一个成功即返回;
- Broadcast Cluster:广播逐个调用所有提供者,任意一个报错则报错。
负载均衡策略
- Random LoadBalance(默认):随机,按权重设置随机概率;
- RoundRobin LoadBalance:轮询,按公约后的权重设置轮询比率;
- LeastActive LoadBalance:最少活跃调用数,相同活跃数的随机;
- ConsistentHash LoadBalance:一致性Hash,相同参数的请求总是发到同一提供者。
MyBatis
mybatis是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。
优点
- 简单易学,容易上手(相比于Hibernate) —- 基于SQL编程;
- JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接;
- 很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持,而JDBC提供了可扩展性,所以只要这个数据库有针对Java的jar包就可以就可以与MyBatis兼容),开发人员不需要考虑数据库的差异性。
- 提供了很多第三方插件(分页插件 / 逆向工程);
- 能够与Spring很好的集成;
- MyBatis相当灵活,不会对应用程序或者数据库的现有设计强加任何影响,SQL写在XML里,从程序代码中彻底分离,解除sql与程序代码的耦合,便于统一管理和优化,并可重用。
- 提供XML标签,支持编写动态SQL语句。
- 提供映射标签,支持对象与数据库的ORM字段关系映射。
- 提供对象关系映射标签,支持对象关系组建维护。
缺点
- SQL语句的编写工作量较大,尤其是字段多、关联表多时,更是如此,对开发人员编写SQL语句的功底有一定要求;
- SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。
Xml映射文件与Mapper接口的工作原理
- 接口的全限名,就是映射文件中的namespace的值;
- 接口的方法名,就是映射文件中MappedStatement的id值;
- 接口方法内的参数,就是传递给sql的参数;
- Mapper接口是没有实现类的,当调用接口方法时,接口全限名 方法名拼接字符串作为key值,可唯一定位一个MappedStatement;
- Mapper接口里的方法,是不能重载的,因为是全限名 方法名的保存和寻找策略。
Mapper接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Mapper接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。
Mybatis的一级、二级缓存
- 一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存。
- 二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置 ;
- 对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。
编程步骤
- 创建SqlSessionFactory;
- 通过SqlSessionFactory创建SqlSession;
- 通过sqlsession执行数据库操作;
- 调用session.commit()提交事务;
- 调用session.close()关闭会话。
#{}和${}的区别
- #{}是预编译处理,${}是字符串替换;
- Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
- Mybatis在处理{}时,就是把{}替换成变量的值;
- 使用#{}可以有效的防止SQL注入,提高系统安全性;
- 使用#{}时,会加单引号的,而${}是不会加单引号的。
Zookeeper
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
客户端的读请求可以被集群中的任意一台机器处理,如果读请求在节点上注册了监听器,这个监听器也是由所连接的zookeeper机器来处理。对于写请求,这些请求会同时发给其他zookeeper机器并且达成一致后,请求才会返回成功。因此,随着zookeeper的集群机器增多,读请求的吞吐会提高但是写请求的吞吐会下降。
有序性是zookeeper中非常重要的一个特性,所有的更新都是全局有序的,每个更新都有一个唯一的时间戳,这个时间戳称为zxid(Zookeeper Transaction Id)。而读请求只会相对于更新有序,也就是读请求的返回结果中会带有这个zookeeper最新的zxid。
工作原理
Zookeeper 的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和 leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。
特点
- 顺序一致性:从同一客户端发起的事务请求,最终将会严格地按照顺序被应用到 ZooKeeper 中去。
- 原子性:所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,也就是说,要么整个集群中所有的机器都成功应用了某一个事务,要么都没有应用。
- 单一系统映像:无论客户端连到哪一个 ZooKeeper 服务器上,其看到的服务端数据模型都是一致的。
- 可靠性:一旦一次更改请求被应用,更改的结果就会被持久化,直到被下一次更改覆盖。
通知机制
client端会对某个znode建立一个watcher事件,当该znode发生变化时,这些client会收到zk的通知,然后client可以根据znode变化来做出业务上的改变等。
四种类型的znode
- PERSISTENT-持久化目录节点 :客户端与zookeeper断开连接后,该节点依旧存在 ;
- PERSISTENT_SEQUENTIAL-持久化顺序编号目录节点:客户端与zookeeper断开连接后,该节点依旧存在,只是Zookeeper给该节点名称进行顺序编号 ;
- EPHEMERAL-临时目录节点:客户端与zookeeper断开连接后,该节点被删除 ;
- EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点:客户端与zookeeper断开连接后,该节点被删除,只是Zookeeper给该节点名称进行顺序编号。
Server的工作状态
- LOOKING:当前Server不知道leader是谁,正在搜寻;
- LEADING:当前Server即为选举出来的leader;
- FOLLOWING:leader已经选举出来,当前Server与之同步。
Docker
Docker是一个容器化平台,它以容器的形式将您的应用程序及其所有依赖项打包在一起,以确保您的应用程序在任何环境中无缝运行。
与虚拟机有何不同
Docker不是虚拟化方法。它依赖于实际实现基于容器的虚拟化或操作系统级虚拟化的其他工具。为此,Docker最初使用LXC驱动程序,然后移动到libcontainer现在重命名为runc。Docker主要专注于在应用程序容器内自动部署应用程序。应用程序容器旨在打包和运行单个服务,而系统容器则设计为运行多个进程,如虚拟机。因此,Docker被视为容器化系统上的容器管理或应用程序部署工具。
- 容器不需要引导操作系统内核,因此可以在不到一秒的时间内创建容器。此功能使基于容器的虚拟化比其他虚拟化方法更加独特和可取。
- 由于基于容器的虚拟化为主机增加了很少或没有开销,因此基于容器的虚拟化具有接近本机的性能。
- 对于基于容器的虚拟化,与其他虚拟化不同,不需要其他软件。
- 主机上的所有容器共享主机的调度程序,从而节省了额外资源的需求。
- 与虚拟机映像相比,容器状态(Docker或LXC映像)的大小很小,因此容器映像很容易分发。
- 容器中的资源管理是通过cgroup实现的。Cgroups不允许容器消耗比分配给它们更多的资源。虽然主机的所有资源都在虚拟机中可见,但无法使用。这可以通过在容器和主机上同时运行top或htop来实现。所有环境的输出看起来都很相似。
Docker镜像
Docker镜像是Docker容器的源代码,Docker镜像用于创建容器。使用build命令创建镜像。
Docker容器
Docker容器包括应用程序及其所有依赖项,作为操作系统的独立进程运行。
容器的四种状态
- 运行
- 已暂停
- 重新启动
- 已退出
Dockerfile中最常见的指令
- FROM:指定基础镜像
- LABEL:功能是为镜像指定标签
- RUN:运行指定的命令
- CMD:容器启动时要运行的命令
常用命令
- docker pull 拉取或者更新指定镜像
- docker push 将镜像推送至远程仓库
- docker rm 删除容器
- docker rmi 删除镜像
- docker images 列出所有镜像
- docker ps 列出所有容器
容器与主机之间的数据拷贝命令
docker cp 命令用于容器与主机之间的数据拷贝
主机到容器:
代码语言:javascript复制docker cp /www 96f7f14e99ab:/www/
容器到主机:
代码语言:javascript复制docker cp 96f7f14e99ab:/www /tmp/
监控Docker
- Docker提供docker stats和docker事件等工具来监控生产中的Docker。我们可以使用这些命令获取重要统计数据的报告。
- Docker统计数据:当我们使用容器ID调用docker stats时,我们获得容器的CPU,内存使用情况等。它类似于Linux中的top命令。
- Docker事件:Docker事件是一个命令,用于查看Docker守护程序中正在进行的活动流。
一些常见的Docker事件是:attach,commit,die,detach,rename,destroy等。我们还可以使用各种选项来限制或过滤我们感兴趣的事件
Jenkins
Jenkins是一个开源的、可扩展的持续集成、交付、部署(软件/代码的编译、打包、部署)的基于web界面的平台。允许持续集成和持续交付项目,无论用的是什么平台,可以处理任何类型的构建或持续集成。
优点
Jenkins是一种使用Java编程语言编写的开源持续集成软件工具,用于实时测试和报告较大代码库中的孤立更改。Jenkins软件使开发人员能够快速找到并解决代码库中的缺陷,并自动进行构建测试。
- 在开发环境的早期阶段, 错误跟踪很容易。
- 提供大量的插件支持。
- 对代码的迭代改进。
- 构建失败会在集成阶段进行缓存。
- 对于每个代码提交更改, 都会生成一个自动生成报告通知。
- 为了将构建报告的成功或失败通知开发人员, 它与LDAP邮件服务器集成在一起。
- 实现持续集成的敏捷开发和测试驱动的开发。
- 通过简单的步骤, 即可自动完成maven发布项目。
CI/CD
- CI(Continuous integration)持续集成: 是一种软件开发时间。持续集成强调开发人员提交了新代码之后,立刻进行构建、(单元)测试。根据测试结果,我们可以确定新代码和原有代码能否正确地集成在一起。
- CD(Continuous Delivery)持续交付: 是在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境(类生产环境)中。比如,我们完成单元测试后,可以把代码部署到连接数据库的Staging环境中更多的测试。如果代码没有问题,可以继续手动部署到生产环境。