JAVA~kuang驾(自记录)

主要进行一些框架小知识的概述~

Spring

控制反转就是依赖倒置原则的一种代码设计的思路。具体采用的方法就是所谓的依赖注入。

Spring事务管理的隔离级别以及传播特性(TODO)

隔离级别
在这里插入图片描述

传播机制:

Spring的API设计很不错,基本上根据英文翻译就能知道作用:
Required:必须的。说明必须要有事物,没有就新建事物。
supports:支持。说明仅仅是支持事务,没有事务就非事务方式执行。
mandatory:强制的。说明一定要有事务,没有事务就抛出异常。
required_new:必须新建事物。如果当前存在事物就挂起。
not_supported:不支持事物,如果存在事物就挂起。
never:绝不有事务。如果存在事物就抛出异常
在这里插入图片描述
在这里插入图片描述

Spring框架中的单例bean是线程安全的吗

在这里插入图片描述

Spring框架中使用了哪些设计模式以及应用场景

在这里插入图片描述

Spring中提供配置元数据的方法

常用的3中配置元数据的方法:基于Java、基于注解(annotation)、基于xml(常用)。

在Java中一个类每个属性都具有set和get方法,就认为这个Java对象是个Bean。
而在一个项目中,有那么多的类,是如何知道Bean的呢?这就需要引入Spring的配置元数据概念:向Spring容器提供相关信息,以便实例化Bean,并指定如何对这些Bean进行装配。所提供的信息称为配置元数据(configuration metadata)。
亦及Bean初始化时所需要的配置参数

Bean后置处理器的用法:实现BeanPostProcessor接口:
postProcessBeforeInitialization() 该方法在注入的Bean的init方法执行前执行
postProcessAfterInitialization() 该方法在注入的Bean的init方法执行后执行

解决循环依赖

Java中的循环依赖分两种,一种是构造器的循环依赖,另一种是属性的循环依赖。

构造器的循环依赖就是在构造器中有属性循环依赖,这种循环依赖没有什么解决办法,因为JVM虚拟机在对类进行实例化的时候,需先实例化构造器的参数,而由于循环引用这个参数无法提前实例化,故只能抛出错误。
Spring解决的循环依赖就是指属性的循环依赖。

一句话:Spring通过将实例化后的对象提前暴露给Spring容器中的singletonFactories,解决了循环依赖的问题。
对于循环依赖的场景,构造器注入和prototype类型的属性注入都会初始化Bean失败。因为@Service默认是单例的,所以单例的属性注入是可以成功的。
参考链接

spring解决这个循环依赖问题主要靠巧妙的三层缓存,所谓的缓存主要是指这三个map,singletonObjects主要存放的是单例对象,属于第一级缓存;singletonFactories属于单例工厂对象,属于第三级缓存;earlySingletonObjects属于第二级缓存,如何理解early这个标识呢?它表示只是经过了实例化尚未初始化的对象。Spring首先从singletonObjects(一级缓存)中尝试获取,如果获取不到并且对象在创建中,则尝试从earlySingletonObjects(二级缓存)中获取,如果还是获取不到并且允许从singletonFactories通过getObject获取,则通过singletonFactory.getObject()(三级缓存)获取。如果获取到了则移除对应的singletonFactory,将singletonObject放入到earlySingletonObjects,其实就是将三级缓存提升到二级缓存,这个就是缓存升级。spring在进行对象创建的时候,会依次从一级、二级、三级缓存中寻找对象,如果找到直接返回。由于是初次创建,只能从第三级缓存中找到(实例化阶段放入进去的),创建完实例,然后将缓存放到第一级缓存中。下次循环依赖的再直接从一级缓存中就可以拿到实例对象了。
在这里插入图片描述
在这里插入图片描述

参考链接

Spring Bean的生命周期

Spring Bean的生命周期简单分为四个阶段多个扩展点。扩展点又可以分为影响多个Bean和影响单个Bean。整理如下:
1、四个阶段

实例化 Instantiation( AbstractAutowireCapableBeanFactory.doCreateBean中会调用createBeanInstance()方法)
属性赋值 Populate
初始化 Initialization
销毁 Destruction

spring的BeanPostProcessor处理器:spring的另一个强大之处就是允许开发者自定义扩展bean的初始化过程,最主要的实现思路就是通过BeanPostProcessor来实现的,spring有各种前置和后置处理器,这些处理器渗透在bean创建的前前后后,穿插在spring生命周期的各个阶段
BeanPostProcessor
InstantiationAwareBeanPostProcessor

这两个可能是Spring扩展中最重要的两个接口!InstantiationAwareBeanPostProcessor作用于实例化阶段的前后,BeanPostProcessor作用于初始化阶段的前后。正好和第一、第三个生命周期阶段对应。
InstantiationAwareBeanPostProcessor实际上继承了BeanPostProcessor接口
来源https://www.jianshu.com/p/1dec08d290c1
(上图来源https://www.jianshu.com/p/1dec08d290c1)

参考链接

2、多个扩展点

影响多个Bean
BeanPostProcessor
InstantiationAwareBeanPostProcessor
影响单个Bean
Aware
Aware Group1
BeanNameAware
BeanClassLoaderAware
BeanFactoryAware
Aware Group2
EnvironmentAware
EmbeddedValueResolverAware
ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware)
生命周期
InitializingBean
DisposableBean

参考链接

AOP

AOP(Aspect Orient Programming),一般称为面向切面编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。AOP实现的关键在于AOP框架自动创建的AOP代理,AOP代理主要分为静态代理和动态代理静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。静态代理是编译期实现,动态代理是运行期实现,可想而知前者拥有更好的性能。

Spring AOP的两种代理实现机制,JDK动态代理和CGLIB动态代理。
静态代理是编译阶段生成AOP代理类,也就是说生成的字节码就织入了增强后的AOP对象;动态代理则不会修改字节码,而是在内存中临时生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

Spring AOP面向切面编程

  • Spring AOP的动态代理主要有两种方式实现,JDK动态代理和cglib动态代理
    • JDK动态代理通过反射来接收被代理的类,但是被代理的类必须实现接口,核心是InvocationHandler和Proxy类。
    • cglib动态代理的类一般是没有实现接口的类,cglib是一个代码生成的类库,可以在运行时动态生成某个类的子类,所以,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

链接

链接2

SpringMVC运行流程

前端先将请求发送给DispatcherServlet
DispatcherServlet查询一个或者多个HanderMapping,找到处理请求的controller
DispatcherServlet再把请求提交到对应的controller;
controller进行业务逻辑处理之后,会返回一个ModelAndView
Dispatcher查询一个或者多个ViewResolver视图解析器,找到ModelAndView对象指定的视图对象;
视图对象负责渲染返回给客户端。

Mybatis

分页插件

PageHelper官网

PageHelper中startPage开启分页方法只对后面的sql查询起作用。

PageHelper 分页无效的案例

#{}和${}

1.#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号,#{}表示一个占位符号,通过#{} 可以实现预编译阶段在使用jdbc时的preparedStatement,sql语句中如果存在参数则会使用?作占位符。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by “111”, 如果传入的值是id,则解析成的sql为order by “id”,显然无用。
2.$将传入的数据直接显示生成在sql中,不会当做字符串处理,是什么就是什么。如:order by $user_id $, 如果传入的值是111,那么解析成sql时的值为order by 111, 如果传入的值是id,则解析成的sql为order by id.
3. #方式能够很大程度防止sql注入。 
4. $ 方式无法防止Sql注入。
5. $ 方式一般用于传入数据库对象,例如传入表名. 
6.一般能用#的就别用$.

xml中sql语句中in的写法

在XML中主要使用foreach标签

传入的参数必须为collection类型的,List 、Map,如果在地址栏接收到的是字符串,那需要转为collection类型
foreach的结果为:(23,46,75,43) 这种形式
foreach元素的属性主要有 item,index,collection,open,separator,close。

<foreach  item="item" collection="listTag" index="index"  open="(" separator="," close=")">
#{item}
</foreach>

# item表示集合中每一个元素进行迭代时的别名.
# index指 定一个名字,用于表示在迭代过程中,每次迭代到的位置.
# collection 为传进来的collection参数的 *类型*
# open表示该语句以什么开始
# separator表示在每次进行迭代之间以什么符号作为分隔符
# close表示以什么结束

参考链接

常用sql

<!-- 查询条件 -->
        <if test="monthQuery != null and monthQuery != ''">
            AND date_format(oi.finish_time,'%Y-%m') = #{monthQuery}
        </if>
<!-- 集合查询条件 -->
<if test="engineerIdList != null">
            AND oe.engineer_id IN
            <foreach collection="engineerIdList" item="engineerId" open="(" close=")" separator=",">
                #{engineerId}
            </foreach>
        </if>
    <!-- 选择查询条件 -->
    <if test="draftState != null">
      <choose>
        <when test="draftState == 0"><!--草稿状态 -->
          and oi.order_state = 0
        </when>
        <when test="draftState == 1"><!-- 已提交状态 -->
          and oi.order_state BETWEEN 1 AND 4
        </when>
      </choose>
    </if>
     <!-- 时间查询条件 -->
    <if test="beginTime != null">
            AND oi.create_time <![CDATA[ >= ]]> #{beginTime}
        </if>
        <if test="endTime != null">
            AND oi.create_time <![CDATA[ <= ]]> #{endTime}
        </if>
    
    <!-- where条件-->
    <where>
            <if test="engineerId != null">
                and engineer_id = #{engineerId,jdbcType=BIGINT}
            </if>
            <if test="engineerIds != null">
                and engineer_id in
                <foreach collection="engineerIds" index="index" item="engineerId" open="(" separator="," close=")">
                    #{engineerId}
                </foreach>
            </if>
        </where>
更改表字段为递增
首先设置一个变量,初始值为任意数值,这里以0为例:
SET @num:= 0;
更新xh(序号)这个字段的值。处理如下:
UPDATE t_table SET xh=(@num:= @num+1)

结果如下:
在这里插入图片描述

一列的值复制给另一列,null时为某值
update T_TABLE set COLUMN_TWO = (case
WHEN COLUMN_ONE  is null THEN 某值
ELSE COLUMN_ONE
END
)

分布式、集群、微服务

集群是个物理形态,分布式是个工作方式。微服务是一种架构风格。

分布式:一个业务拆分成多个子业务,每个子业务分别部署在不同的服务器上
集群:同一个业务,部署在多个服务器上
微服务:是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服务仅关注于完成一件任务并很好地完成该任务。在所有情况下,每个任务代表着一个小的业务能力。

1、分布式是指将不同的子业务分布在不同的地方。而集群指的是将几台服务器集中在一起,实现同一业务。
2、简单说,分布式是以缩短单个任务的执行时间来提升效率的,而集群则是通过提高单位时间内执行的任务数来提升效率。
在这里插入图片描述

参考链接1
参考链接2

CAP原理

CAP理论指的是一个分布式系统最多只能同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance)这三项中的两项。

一致性指的是所有节点在同一时间的数据完全一致;
可用性(A):保证每个请求不管成功或者失败都有响应。
分区容错性指在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性和可用性的服务。就好比是节点出现故障,但是依然可以很好地对外提供服务。

SpringBoot

自动装配、约定大于配置

Spring Boot的启动类上有一个必不可少的@SpringBootApplication注解,一个复合注解或派生注解。包含了:@SpringBootConfiguration,@EnableAutoConfiguration,@ComponentScan

pring Boot有一个全局配置文件:application.properties或application.yml。
我们的各种属性都可以在这个文件中进行配置,最常配置的比如:server.port、logging.level.* 等等

Spring Boot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。

SpringBoot自动装配原理

总结:到这里基本清楚了,springboot的自动装配就是通过自定义实现ImportSelector接口,从而导致项目启动时会自动将所有项目META-INF/spring.factories路径下的配置类注入到spring容器中,从而实现了自动装配。
在这里插入图片描述

参考链接1

参考链接2

为什么要用 Spring Boot

Spring Boot 最重要的功能是:自动配置

为什么说是自动配置?
Spring Boot 的开启注解是:@SpringBootApplication,其实它就是由下面三个注解组成的:
@Configuration
@ComponentScan
@EnableAutoConfiguration

上面三个注解,前面两个都是 Spring 自带的,和 Spring Boot 无关。
所以说 Spring Boot 最最核心的就是这个 @EnableAutoConfiguration 注解了,它能根据类路径下的 jar 包和配置动态加载配置和注入bean。

举个例子,比如我在 lib 下放一个 druid 连接池的 jar 包,然后在 application.yml 文件配置 druid 相关的参数,Spring Boot 就能够自动配置所有我们需要的东西,如果我把 jar 包拿掉或者把参数去掉,那 Spring Boot 就不会自动配置。

这样我们就能把许多功能做成公共的自动配置的启动器(starters),其实 druid 连接池就是这么做的,它提供了针对 Spring Boot 的启动器:druid-spring-boot-starter。

有了这个自动配置的启动器,我们就能非常简单的使用它,

先添加 jar 包依赖:

<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid-spring-boot-starter</artifactId>
   <version>1.1.10</version>
</dependency>

再添加相关参数:

spring.datasource.url= 
spring.datasource.username=
spring.datasource.password=
……

如果是传统的项目,我们要自己手动写一大堆的配置,而且还不灵活,有了这个启动器,我们就可以做到简单集成。
参考链接

SpringCloud

在这里插入图片描述
springCloud的基本功能:
服务治理:Spring Cloud Eureka
客户端负载均衡:Spring Cloud Ribbon
服务容错保护:Spring Cloud Hystrix
声明式服务调用:Spring Cloud Feign
API网关服务:Spring Cloud Zuul
分布式配置中心:Spring Cloud Config
消息总线:Spring Cloud Bus
消息驱动的微服务:Spring Cloud Stream
分布式服务跟踪:Spring Cloud Sleuth

Dubbo和Zookeeper

shiro

在这里插入图片描述

RPC

即远程过程调用。核心模块:通讯和序列化。

Dubbo

高可用的RPC通信框架。
三大核心:面向接口的远程方法调用;
智能容器和负载均衡;
服务自动注册和发现

Zookeeper

注册中心。服务注册与发现。

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Middleware

gateway: 网关
nacos: 分布式配置中心。
consul: 服务注册与发现中心。
msyql: 关系型数据库,存储业务数据。
mongo: 文档数据库,用户大量读场景。
redis: 分布式缓存服务。
rocketmq: 分布式消息队列服务。
elasticsearch: 搜索引擎。
xxl-job: 分布式任务调度服务。
efk: 日志收集与查询服务
skywalking: 链路追踪服务。
prometheus: 应用监控服务。
seata: 分布式事务服务。

RocketMQ

如何保证消息不丢失

分别从Producer发送机制、Broker的持久化机制,以及消费者的offSet机制来最大程度保证消息不易丢失

https://blog.csdn.net/leeasony/article/details/104857576
https://baijiahao.baidu.com/s?id=1662095398693413299&wfr=spider&for=pc

Redis

redis是基于内存的key-value数据库,非关系型数据库 可持久化

Redis 是一个开源的使用 ANSI C 语言编写、遵守 BSD 协议、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API的非关系型数据库。

传统数据库遵循 ACID 规则。而 Nosql(Not Only SQL 的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称) 一般为分布式而分布式一般遵循 CAP 定理。

支持丰富数据类型,支持string,list,set,sorted set,hash

数据类型格 式描述
String 字符串set key valuestring类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。string类型是Redis最基本的数据类型,一个键最大能存储512MB。
Hash 哈希HMSET key field1 value1 [field2 value2 ]Redis hash 是一个键值(key=>value)对集合。Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。同时将多个 field-value (域-值)对设置到哈希表 key 中。
List(列表)LPUSH key value1 [value2]将一个或多个值插入到列表头部
RPUSH key value1[value2]在 key 对应 list 的尾部添加字符串元素
Set(集合)SADD key member1 [member2]向集合添加一个或多个成员。Redis的Set是string类型的无序集合。集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
zset(sorted set:有序集合)ZADD key score1 member1 [score2 member2]向有序集合添加一个或多个成员,或者更新已存在成员的分数。Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。zset的成员是唯一的,但分数(score)却可以重复。

参考链接

Q1、什么是Redis持久化?Redis有哪几种持久化方式?优缺点是什么?
1、持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失。

2、Redis 提供了两种持久化方式:RDB(默认)(Redis DataBase)和AOF(Append Only File)。

一种是RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化)。RDB 快照:在默认情况下, Redis 将数据库快照保存在名字为 dump.rdb 的二进制文件中。
另外一种是AOF持久化(原理是将Reids的操作日志以追加的方式写入文件)

3、优劣势
RDB:
(1)RDB文件紧凑,全量备份,非常适合用于进行备份和灾难恢复。
(2)生成RDB文件的时候,redis主进程会fork()一个子进程来处理所有保存工作,主进程不需要进行任何磁盘IO操作。
(3)RDB 在恢复大数据集时的速度比 AOF 的恢复速度要快

但在快照持久化期间修改的数据不会被保存,可能丢失数据。。(RDB快照是一次全量备份,存储的是内存数据的二进制序列化形式,存储上非常紧凑。当进行快照持久化时,会开启一个子进程专门负责快照持久化,子进程会拥有父进程的内存数据,父进程修改内存子进程不会反应出来,所以在快照持久化期间修改的数据不会被保存,可能丢失数据。)

AOF:
工作机制很简单,redis会将每一个收到的写命令都通过write函数追加到文件中。通俗的理解就是日志记录。
(1)AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据。
(2)AOF日志文件没有任何磁盘寻址的开销,写入性能非常高,文件不容易破损。
(3)AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。
(4)AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据

缺点
(1)对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大
(2)AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的
(3)以前AOF发生过bug,就是通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来

总结:
1、aof文件比rdb更新频率高,优先使用aof还原数据。
2、aof比rdb更安全也更大
3、rdb性能比aof好
4、如果两个都配了优先加载AOF

Q2、什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免?

缓存穿透

一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

如何避免?

1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。

2:对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。
3:布隆过滤器 hash 可以判断没有的key。有一定错误率,判断某样东西一定不存在或者可能存在

缓存击穿
是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力(某个key突然过期,高并发访问,打到数据库)

如何避免?

1:设置热点数据永远不过期。
2:使用互斥锁

参考链接

缓存雪崩

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力。导致系统崩溃。

如何避免?

1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

2:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期

3:不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

Redis 分布式锁过期了,但业务还没有执行完,怎么办

设置锁成功后,启动一个watchdog,每隔一段时间(比如10s)为当前分布式锁续约,也就是每隔10s重新设置当前key的超时时间。命令如下:
EXPIRE < key > < seconds >

https://zhuanlan.zhihu.com/p/421843030
https://blog.csdn.net/xj80231314/article/details/93719829

java操作redis缓存设置过期时间

jedisClient
https://blog.csdn.net/xj80231314/article/details/93719829

Consul

Consul 是 HashiCorp 公司推出的开源产品,用于实现分布式系统的服务发现、服务隔离、服务配置,这些功能中的每一个都可以根据需要单独使用,也可以同时使用所有功能。
与其它分布式服务注册与发现的方案相比,Consul 的方案更“一站式”——内置了服务注册与发现框架、分布一致性协议实现、健康检查、Key/Value 存储、多数据中心方案,不再需要依赖其它工具。Consul 本身使用 go 语言开发,具有跨平台、运行高效等特点,也非常方便和 Docker 配合使用。

在 Spring Cloud 体系中,几乎每个角色都会有两个以上的产品提供选择,比如在注册中心有:Eureka、Consul、zookeeper、etcd 等;网关的产品有 Zuul、Spring Cloud Gateway 等。

此处使用Consul作为注册中心、服务注册与发现。
Service Discovery : 服务注册与发现,Consul 的客户端可以做为一个服务注册到 Consul,也可以通过 Consul 来查找特定的服务提供者,并且根据提供的信息进行调用。

支持多数据中心,内外网的服务采用不同的端口进行监听。多数据中心集群可以避免单数据中心的单点故障,而其部署则需要考虑网络延迟, 分片等情况等。 zookeeper 和 etcd 均不提供多数据中心功能的支持。
支持健康检查。 etcd 不提供此功能。
支持 http 和 dns 协议接口。 zookeeper 的集成较为复杂, etcd 只支持 http 协议。
官方提供 Web 管理界面, etcd 无此功能。
Consul 保持了 CAP 中的 CP,保持了强一致性和分区容错性。
Consul 支持 Http\gRPC\DNS 多种访问方式。

在这里插入图片描述
通过对比可以得知, Consul 功能更强大,Euerka 更容易使用。
Consul 强一致性©带来的是:
服务注册相比 Eureka 会稍慢一些。因为 Consul 的 raft 协议要求必须过半数的节点都写入成功才认为注册成功,。Leader 挂掉时,重新选举期间整个 Consul 不可用。保证了强一致性但牺牲了可用性
Consul 强烈的一致性意味着它可以作为领导选举和集群协调的锁定服务。

Eureka 保证高可用(A)和最终一致性:
服务注册相对要快,因为不需要等注册信息 replicate 到其它节点,也不保证注册信息是否 replicate 成功。当数据出现不一致时,虽然 A, B 上的注册信息不完全相同,但每个 Eureka 节点依然能够正常对外提供服务,这会出现查询服务信息时如果请求 A 查不到,但请求 B 就能查到。如此保证了可用性但牺牲了一致性

参考链接

什么是服务发现

总的来说,服务发现就是程序如何通过一个标志来获取服务列表,并且这个服务列表是能够随着服务的状态而动态变更的。

Nacos

Nacos 支持基于 DNS 和基于 RPC 的服务发现(可以作为springcloud的注册中心)、动态配置服务(可以做配置中心)、动态 DNS 服务。
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您实现动态服务发现、服务配置管理、服务及流量管理

官方网址:http://nacos.io 默认占用的端口是8848

作为配置管理,需要添加依赖:

<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  <version>0.2.0.RELEASE</version>
</dependency>

作为服务发现,添加依赖:

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    <version>${latest.version}</version>
</dependency>

图形化界面:
在这里插入图片描述
在这里插入图片描述

在项目启动时就会去配置中心去读取配置信息(本地的配置文件application.properties还能用,但优先级低于配置中心的配置)

栗子:
在启动类,加入@NacosPropertySource注解其中包含两个属性,如下:

dataId:这个属性是需要在Nacos中配置的Data Id。
autoRefreshed:为true的话开启自动更新。
在使用Nacos做配置中心后,需要使用@NacosValue注解获取配置,使用方式与@Value一样,完整启动类代码如下所示。

@SpringBootApplication
@NacosPropertySource(dataId = "springboot2-nacos-config", autoRefreshed = true)
@RestController
public class Springboot2NacosConfigApplication {

	public static void main(String[] args) {
		SpringApplication.run(Springboot2NacosConfigApplication.class, args);
	}

	@NacosValue(value = "${nacos.test.propertie:123}", autoRefreshed = true)
	private String testProperties;

	@GetMapping("/test")
	public String test(){
		return testProperties;
	}
}

3月20号,Nacos 2.0.0 正式发布了!
Nacos 2.0 架构最主要的变化就是增加了对长连接的支持,gRPC 和 Rsocket 实现了长连接 RPC 调用和推送能力。

参考链接

面试:Nacos获取配置时启用权限认证

只要nacos.core.auth.enabled 设置为 true 就行了.

OpenFeign

feign 请求底层是通过 RestTemplate 进行请求

OpenFeign为微服务架构下服务之间的调用提供了解决方案,OpenFeign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用OpenFeign,可以做到使用HTTP请求访问远程服务,就像调用本地方法一样的,开发者完全感知不到这是在调用远程方法,更感知不到在访问HTTP请求。


总结:
openFeign生成@FeignClient注解的接口的代理对象是从FeignClientFactoryBean的getObject方法开始的,生成proxy对象主要由ReflectiveFeign对象来实现。动态代理方法由jdk原生的动态代理支持。
调用proxy对象,其实就是发起http请求,请求结果将被解码并返回。
所以,正如Feign本身的意义一样,http远程调用被伪装成了本地调用一样简单的代理对象,对于使用者来说就是调用本地接口一样简单。


再总结:
feign作用就是通过动态代理 把注解和方法这些都拼装 变成http请求地址 然后调用下游
feign注解 + 方法上的注解都加上

//----------接口----------
@FeignClient(value = AppConstant.APP_SERVICE_COMPANY,path = "/companyInfo")
public interface ICompanyInfoClient {
    @PostMapping("/deleteByPrimaryKey")
    int deleteByPrimaryKey(@RequestParam("id") Long id);
。。。
}
//----------controller可以实现feign接口 也可以不实现----------
@RestController
@RequestMapping("/companyInfo")
@Slf4j
public class CompanyInfoClient implements ICompanyInfoClient {
    @Autowired
    private CompanyInfoService companyInfoService;

    @Override
    @PostMapping("/deleteByPrimaryKey")
    public int deleteByPrimaryKey(Long id) {
        return companyInfoService.deleteByPrimaryKey(id);
    }
    。。。
}
//----------调用----------
直接在facade层即上层注入feign接口,并直接调用方法。
CreateCompanyResultVo vo = iCompanyInfoClient.createCompany(dto);

在这里插入图片描述
在这里插入图片描述

使用Feign进行服务降级

feign服务里加上

@FeignClient(value = "patrol-control", fallback = BasePersonFeignFallBack.class,
    path = "/patrol-control")
public interface BasePersonFeignBiz {

  @RequestMapping(value = "/basePerson/findByNumber", method = RequestMethod.GET)
  public ObjectRestResponse<BasePerson> findByNumber(@RequestParam("number") String number);
}

然后服务降级后的服务 直接去实现他 然后重写即可

@Component
public class BasePersonFeignFallBack implements BasePersonFeignBiz {

  @Override
  public ObjectRestResponse<BasePerson> findByNumber(String number) {
    BasePerson basePerson = new BasePerson();
    basePerson.setName("错误人员的信息");
    return new ObjectRestResponse<>().data(basePerson);
  }
}
作者:星星先生9
链接:https://www.jianshu.com/p/5ff356573c60

总结如下链接:
1、Feign 定义熔断降级方法
2、通过 FallbackFactory 工厂 实现降级
https://www.cnblogs.com/zjdxr-up/p/15085498.html

Nginx

Nginx一个高性能的HTTP和反向代理web服务器
Nginx作为负载均衡服务

  • 反向代理
  • 负载均衡
  • HTTP 服务器(包含动静分离)
  • 正向代理

Database SQL

修改字段的长度
语法:
ALTER TABLE 表名 MODIFY COLUMN 字段名 数据类型(修改后的长度)

修改字段的名称
alter table <表名> change <字段名> <字段新名称> <字段的类型>。

新增默认为空的字段
ALTER TABLE 表名 ADD COLUMN 字段名 字段类型 DEFAULT NULL COMMENT ‘备注’;
ALTER TABLE order_company MODIFY brand varchar(200) NOT NULL COMMENT ‘品牌’
新增不为空的字段
ALTER TABLE 表名ADD COLUMN 字段名 字段类型 NOT NUL

删除字段
ALTER TABLE 表名 DROP COLUMN 字段名;

CREATE TABLE order_company (
id bigint(20) NOT NULL AUTO_INCREMENT COMMENT ‘主键ID’,
order_name varchar(100) NOT NULL COMMENT ‘订单名称’,
order_id bigint(20) NOT NULL COMMENT ‘订单实例ID’,
order_num varchar(32) NOT NULL DEFAULT ‘’ COMMENT ‘订单号’,
company_id bigint(20) NOT NULL COMMENT ‘厂商ID’,
company_num varchar(32) NOT NULL COMMENT ‘厂商编号’,
company_name varchar(200) NOT NULL COMMENT ‘厂商名称’,
brand_name varchar(201) NOT NULL COMMENT ‘品牌呀’,
guarantee_type int(1) NOT NULL COMMENT ‘质保类型 1保内 2保外’,
company_order_num varchar(200) NOT NULL DEFAULT ‘’ COMMENT ‘原厂商单号’,
cate_id_one bigint(20) NOT NULL COMMENT ‘一级类目ID’,
cate_id_two bigint(20) NOT NULL COMMENT ‘二级类目ID’,
cate_one_name varchar(100) NOT NULL COMMENT ‘一级类目名’,
cate_two_name varchar(100) NOT NULL COMMENT ‘二级类目名’,
machine_class_id bigint(20) DEFAULT NULL COMMENT ‘家电种类ID’,
machine_class varchar(200) DEFAULT NULL COMMENT ‘家电种类’,
machine_model varchar(200) DEFAULT NULL COMMENT ‘家电型号’,
fault_code varchar(200) DEFAULT NULL COMMENT ‘故障代码’,
serial_num varchar(200) DEFAULT NULL COMMENT ‘序列号’,
create_id bigint(20) NOT NULL COMMENT ‘创建人’,
update_id bigint(20) NOT NULL COMMENT ‘修改人’,
create_time datetime NOT NULL COMMENT ‘创建时间’,
update_time datetime NOT NULL COMMENT ‘更新时间’,
PRIMARY KEY (id) USING BTREE,
UNIQUE KEY order_num (order_num) USING BTREE,
KEY idx_company_id (company_id) USING BTREE,
KEY idx_order_id (order_id) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=293 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT=‘xx表’;

  • 0
    点赞
  • 1
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:游动-白 设计师:我叫白小胖 返回首页

打赏作者

Vegetable_xu

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值