当前位置: 首页 > news >正文

7.Spring框架

# ==spring框架==Spring3.0开启了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道## 为什么要使用 **Spring** 框架?​     Spring 是一个轻量级应用框架,它提供了 IoC 和 AOP 这两个核心的功能。它的核心目的是为了简化企业级应用程序的开发,使得开发者只需要关心业务需求,不需要关心 Bean 的管理,以及通过切面增强功能减少代码的侵入性。从Spring 本身的特性来看,我认为有几个关键点是我们选择 Spring 框架的原因。轻量:Spring 是轻量的,基本的版本大约 2MB。IOC/DI:Spring 通过 IOC 容器实现了 Bean 的生命周期的管理,以及通过 DI 实现依赖注入,从而实现了对象依赖的松耦合管理。面向切面的编程(AOP):Spring 支持面向切面的编程,从而把应用业务逻辑和系统服务分开。MVC 框架:Spring MVC 提供了功能更加强大且更加灵活的 Web 框架支持事务管理:Spring 通过 AOP 实现了事务的统一管理,对应用开发中的事务处理提供了非常灵活的支持,最后,Spring 从第一个版本发布到现在,它的生态已经非常庞大了。在业务开发领域,Spring 生态几乎提供了非常完善的支持,更重要的是社区的活跃度和技术的成熟度都非常高,以上就是我对这个问题的理解## 常用的==注解==​    `@Configuration注解`用于设定当前类为配置类​    `@ComponentScan`注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式​	 `@EnableAspectJAutoProxy` 开启AOP功能​    @Aspect aop注解​     @After后置通知​     @AfterReturn返回后通知​     @AfterThrowing抛异常后通知​     @Around环绕通知​     `@EnableTransactionManagement`开启事务## 实例化==Bean的创建的方式==- **构造方法方式**- **静态工厂方式**- **实例工厂方式**- **实现FactoryBean方式**## 支持几种==bean的域?==@Scope("")singlot (单例模式) 容器生,容器死prototype(原型模式) 调用生,GC死request (http请求) request生 ,响应死session (会话) 30分钟不用自动死globsession  (全局会话) 30分钟不用自动死**如何修改一个Bean的作用域  ?**   @Scope("protoype")## **springbean的==生命周期:==**Spring 生命周期全过程大致分为五个阶段:创建前准备阶段、创建实例阶段、依赖注入阶段、容器缓存阶段和销毁实例阶段一、创建前准备阶段这个阶段主要的作用是,Bean 在开始加载之前,需要从上下文和相关配置中解析并查找 Bean 有关的扩展实现,比如像 init-method-容器在初始化 bean 时调用的方法、destory-method,容器在销毁 bean 时调用的方法。以及,BeanFactoryPostProcessor 这类的 bean 加载过程中的前置和后置处理。这些类或者配置其实是 Spring 提供给开发者,用来实现 Bean 加载过程中的扩展机制,在很多和 Spring 集成的中间件中比较常见,比如 Dubbo。二、创建实例阶段这个阶段主要是通过反射来创建 Bean 的实例对象,并且扫描和解析 Bean 声明的一些属性。三、依赖注入阶段如果被实例化的Bean 存在依赖其他Bean 对象的情况,则需要对这些依赖 bean进行对象注入。比如常见的@Autowired、setter 注入等依赖注入的配置形式。同时 , 在 这个 阶段 会触 发一 些扩 展的 调用 , 比 如常见 的扩 展类 :BeanPostProcessors(用来实现 bean 初始化前后的扩展回调)、InitializingBean(这个类有一个afterPropertiesSet(),这个在工作中也比较常见)、 BeanFactoryAware 等等。四、容器缓存阶段容器缓存阶段主要是把 bean 保存到容器以及 Spring 的缓存中,到了这个阶段,Bean 就可以被开发者使用了。这个阶段涉及到的操作,常见的有,init-method 这个属性配置的方法, 会在这个阶段调用。以 及 像 BeanPostProcessors 方 法 中 的 后 置 处 理 器 方 法 如 :postProcessAfterInitialization,也会在这个阶段触发。五、销毁实例阶段当 Spring 应用上下文关闭时,该上下文中的所有 bean 都会被销毁。如果存在 Bean 实现了 DisposableBean 接口,或者配置了destory-method属性,会在这个阶段被调用。### **spring  ==bean的注入方式==有哪几种**:把 Bean 注入到 IOC 容器里面的方式有 7 种方式;使用 xml 的方式来声明 Bean 的定义,Spring 容器在启动的时候会加载并解析这个 xml,把 bean 装载到 IOC 容器中。使用@CompontScan 注解来扫描声明了@Controller、@Service、@Repository、@Component 注解的类。使用@Configuration 注解声明配置类,并使用@Bean 注解实现 Bean 的定义, 这种方式其实是 xml 配置方式的一种演变,是 Spring 迈入到无配置化时代的里程碑。使用@Import 注解,导入配置类或者普通的 Bean使用 FactoryBean 工厂 bean , 动态构建一个 Bean 实例, Spring Cloud OpenFeign 里面的动态代理实例就是使用 FactoryBean 来实现的。实现 ImportBeanDefinitionRegistrar 接口,可以动态注入 Bean 实例。这个在Spring Boot 里面的启动注解有用到。实现 ImportSelector 接口,动态批量## ==依赖注入==法1.**Set方法注入**:注入最简单,最常用的注入方式,支持注解+xml。2.**构造器注入**:是指带有参数的构造函数注入,支持注解+xml有两种实现方式:
1.**注解**(@Autowired,@Resource,@Required)2.配置文件(xml)## **两大核心==(IOC-AOP)==:**`IOC (控制反转)` :把对象的创建交由Spring, Spring提供了一个容器,称为==IOC容器==,用来充当IoC思想中的“外部”**IOC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象**在IoC容器中统称为==Bean==。【充分解耦,降低了代码的耦合,我们只需要通过配置文件进行操作即可】DI(Dependency Injection)依赖注入:在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入。`AOP(面向切面编程)`:**在不改变源代码的情况下对代码进行增强**   (动态代理 静态织入) ​      作为面向对象的一种补充,用于**将 那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块**,这个模块被命名为“切面”(Aspect),**减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性。**Aop通知的几种类型​	AOP通知共分为5种类型- 前置通知 ==@Before==:在切入点方法执行之前执行
- 后置通知 ==@After==:在切入点方法执行之后执行,==无论切入点方法内部是否出现异常,后置通知都会执==行。
- 返回后通知(了解) ==@AfterReturning==:在切入点方法执行之后执行,==如果切入点方法内部出现异常将不会执行。因为如果出了异常,方法没有执行完毕,方法还有返回值没有返回,所以不执行==。
- **==环绕通知(重点) @Around:==**手动调用切入点方法并对其进行增强的通知方式。
- 抛出异常后通知  @AfterThrowing  (了解):在切入点方法执行之后执行,只有当切入点方法内部出现异常之后才执行。Aop的切面在项目中用的还是比较多的,我 在项目中就使用aop完成日志的统一处理。原来是把日志记录的相关代码分散到各个控制层 的相关方法中,但这就会导致程序员在开发时候不能将经理集中到业务逻辑的处理上,还得 考虑记录日志,工作效率就大打折扣,我在项目中负责过日志管理模块。之后引入日志记录相关就可以了## ==IOC实现原理==                                                                                                                                                                                                                                                        基于Factory工厂来进行Bean对象的创建和管理。  底层是localMap --》ThreadLocalMap## IOC的工作流程​     第一步:准备spring的上下文环境,也就是ApplicationContext,比如XmlConfigApplicationContext,和AnnotationApplicationContext,它们的底层是通过创建bean的工厂,也就是BeanFactory生成bean的,第二步开始扫描XML文件和Annotation注解,得到一个个BeanDefination,bean的定义,这不是真正的bean而是bean的定义,比如说bean的名字,类型,属性,依赖关系。第三步通过applicationContext生成DefaultListableBeanFactory的bean工厂,这个工厂会根据第二步bean的定义创建单例bean,实例化bean然后完成依赖注入,第四步就是把生成的 bean放到ioc容器里,也就是底层的map集合里,大致就是这么个流程。## AOP的工作流程​      aop是ioc的一个扩展功能,先有ioc再有aop,aop是为了在不修改原代码的基础上对方法进行增强,它一般应用的场景是一些日志记录,或者是事务的实现,spring的事务就是用到了aop的思想,**aop的实现是通过jdk的动态代理和cglib实现的,jdk的动态代理只能基于接口创建代理对象**,因为jdk动态代理是继承自proxy类,java只支持单继承,所以创建代理对象只能通过实现自接口的方式创建,cglib是通过父子类来创建代理对象的,所以类不能被final修饰,必须要能被继承。bean的创建过程有一个步骤可以对bean进行扩展,aop本身就是一个功能扩展,所以在beanPostProfessor的后置处理方法中来实现## DI依赖注入​     DI 表示依赖注入,也就是对于 IOC 容器中管理的 Bean,如果 Bean 之间存在依赖关系,那么 IOC 容器需要自动实现依赖对象的实例注入,通常有三种方法来描述 Bean 之间的依赖关系。接口注入setter 注入构造器注入另外,为了更加灵活的实现 Bean 实例的依赖注入,Spring 还提供了@Resource 和@Autowired 这两个注解。分别是根据 bean 的 id 和 bean 的类型来实现依赖注入。## **==Aop 实现原理==**1.`JDK 动态代理` (默认,必须依赖于接口,没有接口,无法对方法进行增强)  2.`cglib` (可以不依赖于接口,但是此类不能被final修饰,cglib基于父子类来实现)## **==项目==中哪些地方用到==AOP==(项目中用到过的哪些设计模式)**1.spring内置的声明式事务     2.方法的日志记录    3.结合google插件实现接口限流  4.给注解进行增强 5.全局异常处理器ControllerAdvice## AOP的==日志==统一处理:日志管理模块:在项目中我做过后台管理系统的日志管理模块,日志管理模块的作用说白了就是记录用户的操作,这样就知道谁在什么时候干了什么事情。​       之前做其他项目的时候,日志处理模块通常都是在控制层结合log4j进行日志的控制台打印以及日志文件的存储,除此之外还会把日志信息插入到mysql数据库中存储起来,方便查看。​       但这样做会有个问题,就是需要在每个Controller类的每个方法中都写上相关的日志记录代码,这样就会出现大量的代码重复,以后维护起来也特别麻烦。​      所以说后面在做日志管理模块的时候,我就考虑到可以使用AOP做统一日志的处理,这样就可以让我们程序员在工作的时候把精力花在核心业务代码的处理上。​         具体在做的时候我是这样写的。首先写一个日志切面类,这个切面类说白了就是一个普通的java类,后面会通过配置文件的配置让他具备切面类的功能。在这个普通的java类中我会自定义一个横切逻辑,说白了就是一个普通的方法,但这个方法中需要特别注意几点,因为当时在项目中我使用的是环绕通知,所以就会让这个方法返回一个Object类型值,再者就是在方法中有一个ProceedingJoinPoint类型的参数。​         具体在写方法的时候有几个特别关键的地方,首先因为要获取当前登录的用户,用户的信息是存储在session中的,我当时采用的解决方案是使用ThreadLocal+Filter来完成在一个普通的java类中获取当前请求的request对象,进而获取存储在session中的用户信息。ThreadLocal可以把它理解成一个Map,但它特殊的地方就是它用当前线程充当key,所以在使用的时候,存储信息用set(value)就行了,之所以没有写key,就是因为当前访问的线程就是默认的key,同理取数据用get();当时我封装了一个工具类,工具类中有个setRequest方法,就是将request对象存储到ThreadLocal中,同样还有个getRequest方法,就是获取当前线程对应的reqeust对象。​        之后我会在自定义的Filter中的doFilter方法中,调用工具类的setRequest方法,将当前请求存储到ThreadLocal中,当然还得在web.xml中配置Filter使其生效。接下来我会在日志切面类中通过调用工具类的getRequest方法来获取request,进而通过getSession来获取session,这样就可以取到存在session中的相关用户信息了。 ​       获取了用户信息之后就要记录用户做了什么事情,在这块我们当时的项目是这么规定格式的,就是要记录用户执行了哪个类的哪个方法,并且要把执行这个方法时候对应的参数信息也给获取到,比如用户添加了一个商品,那   记录的信息就应该是调用了ProductController类的addProduct方法,并且也要获取到添加的商品信息参数,这样才能看的更明白。​       获取类名和方法名这块是通过反射机制,调用ProceedingJoinPoint的相关方法获取的,获取参数信息是通过   request.getParameterMap()之后对其进行循环遍历,这样就获取到了提交时候的参数详情.​       在这整个切面类中还有一个特别重要的方法就是ProceedingJoinPoint.proceed();它代表的就是实际要执行的  核心业务逻辑,它的返回值就是实际执行方法的返回值,比如刚才说的ProductController类中的addProduct方法, 这个proceed()代表的就是addProduct方法,而他的返回值就是控制层中addProduct方法的返回值。之所以 它的返回值类型为Object就是因为不同方法的返回值不一样,但它们都属于Object对象。​      接着我会把proceed方法进行try...catch...捕获,然后在这个方法执行完后记录操作成功的日志并且把日志信息插入数据库,在catch捕获异常的时候记录错误日志,同时会把异常信息记录数据库。​      最后需要在spring的配置文件中配置aop:config以及配置切点表达式来对控制层中的增,删,改方法进行拦截,这里就用到了切点表达式中特殊符号的双竖杠||。​         在上交完任务后,我们经理给我说这个东西,做的整体上还不错,但是有个问题,就是日志虽然记录了操作哪个  类的哪个方法,程序员可以读懂,但业务员根本就看不明白,不够人性化,让我的日志记录再改进下。​       我通过和我们团队的人讨论,最终决定通过自定义注解来完成这个改进。​       在写自定义日志注解时候,通过 @Target 设置为Method指明该注解只能用在方法上面,通过将 @Retention设置为RunTime指明将注解保留至运行时。这样就可以通过反射去获取注解信息。​       在注解中声明了一个String类型的value来让程序员手工设置日志的信息,之所以采用value,是因为value这个字段有特殊的含义,它可以在使用自定义注解给日志信息赋值的时候省略不写,用起来更加方便。之后就可以在Controller中的方法上加入自定义注解并且对value进行日志信息的赋值,如 @Log("增加商品")。​      最后在AOP的日志切面类中通过获取方法签名得到Method,通过Method的isAnnotationPresent判断该方法上面是否加入了自定义日志注解,如果 是 则再通过Method的getAnnotation来获取自定义的日志注解,最后再通过.value()方法获取自定义注解中日志信息的值,这样在记录日志的时候就可以显示更加人性化的信息## **==AOP限流和网关限流的区别:==**AOP限流是对请求接口或者某些方法进行流量限制,网关限流是对服务请求进行流量限制(网关限流一般比接口限流大很多  1000  200)## ==事务==传播==特性/行为==1. `PROPAGATION_REQUIRED`:**支持当前事务**,如果当前没有事务,就==新建==一个事务。这是最常见的选择          2. `PROPAGATION_SUPPORTS`:**支持当前事务**,如果当前没有事务,就以==非事务方式==执行。 3. `PROPAGATION_MANDATORY`:**支持当前事务**,如果当前没有事务,就==抛出异常==。 4. `PROPAGATION_REQUIRES_NEW`:**新建事务,**如果当前存在事务,把==当前事务挂起==。 5. `PROPAGATION_NOT_SUPPORTED`:以**非事务方式执行**操作,如果==当前存在事务,就把当前事务挂起== 6. `PROPAGATION_NEVER`:以**非事务方式执行**,如果==当前存在事务,则抛出异常==。 7. `PROPAGATION_NESTED` :**支持当前事务**,新增Savepoint点,与==当前事务同步提交或回滚==。 ## **==事务不生效==的场景**1.数据库`存储引擎非innerDB` 。2.`注解到非public 方法`上,事务不生效,它也不会报错,不过事务设置不会起作用。3.在`业务层捕捉异常后未向上抛出`,事务不生效。 捕获异常处理掉了,也没法抛异常
原因:在业务层手工捕捉并处理了异常(try..catch)等于把异常“吃”掉了,Spring自然不知道这里有错,更不会主动去回滚数据。推荐**做法是在业务层统一抛出异常,然后在控制层统一处理。**  解决:在catch里面 throw new RuntimeException  来触发aop的异常通知4.遇到**非检测异常**时,事务不开启,也无法回滚。下方图片是异常体系
原因:因为Spring的默认的事务规则是遇到运行异常(RuntimeException)和程序错误(Error)才会回滚。如果想针对非检测异常进行事务回滚,可以在@Transactional 注解里使用rollbackFor 属性明确指定异常。5.不要写到接口上,spring 采用 aop 针对具体实现类做的代理实现。 (spring5.0以上版本可以写在接口上)6.Spring的事务传播策略在内部方法调用时将不起作用,事务注解加到要调用方法上  Propagation.SUPPORTS。7.分布式事务,使用本地事务也无法进行管理   因为跨服务无法保证**所有异常抛开程序异常之外的所有异常一定能被Execption拦截吗?**不能,拦截不了Execption父类Throwable 异常## ==spring 和 springBoot 和spring cloud== 的==区别==spring是spring旗下的家族核心框架,主要作用用来解决类与类之间的耦合度  + 聊其核心(IOC+Aop)springboot,快速构建一个spring环境的框架, 底层本质依然是spring   springcloud 他是很多技术框架的一个集合,主要用来构建整个微服务体系架构   + 聊其核心(五大核心组件)##  ## **为什么需要==三级缓存==(作用):**

三级缓存是用来存储代理 Bean,当调用 getBean()方法时,发现目标 Bean 需要通过代理工厂来创建,此时会将创建好的实例保存到三级缓存,最终也会将赋值好的 Bean 同步到一级缓存中。

二级缓存解决不了有aop的循环依赖。spring采用了三级缓存。 如果创建的`Bean`有对应的`代理`,那其他对象注入时,注入的应该是对应的`代理对象`;但是`Spring`无法提前知道这个对象是不是有`循环依赖`的情况,而`正常情况`下(没有`循环依赖`情况),`Spring`都是在创建好`完成品Bean`之后才创建对应的`代理`。 ## ==不能解决循环依赖==

有四种情况:

  1. 多例 Bean 通过 setter 注入的情况,不能解决循环依赖问题

  2. 构造器注入的 Bean 的情况,不能解决循环依赖问题

  3. 单例的代理 Bean 通过 Setter 注入的情况,不能解决循环依赖问题

4.设置了@DependsOn 的 Bean 的情况,不能解决循环依赖问题

## **Spring** ==解决循环依赖==我们都知道,如果在代码中,将两个或多个 Bean 互相之间持有对方的引用就会发生循环依赖。循环的依赖将会导致注入死循环。这是 Spring 发生循环依赖的原因。循环依赖有三种形态:第一种互相依赖:A 依赖 B,B 又依赖 A,它们之间形成了循环依赖。第二种三者间依赖:A 依赖 B,B 依赖 C,C 又依赖 A,形成了循环依赖。第三种是自我依赖:A 依赖 A 形成了循环依赖。三级缓存:**第一级缓存**〈也叫单例池)`singletonObjects`:存放已经经历了完整生命周期的Bean对象**第二级缓存**: `earlySingletonObjects`:存放早期暴露出来的Bean对象,Bean的生命周期未结束(属性还未填充完整)**第三级缓存**: `Map<String, ObiectFactory<?>> singletonFactories`,**存放可以生成Bean的工厂**。​       话术: 循环依赖就是在A创建对象的时候会依赖B,在创建B对象的时候会创建A,解决的原理是spring的三级缓存,第一级缓存存放完整的bean对象,二级缓存存放的是早期暴露出来的bean对象,bean的生命周期并未结束(属性还没有填充完整),三级缓存存放的是创建bean的工厂。具体的创建流程就是当创建A对象是,会发现需要创建B对象,这是A对象将自己放入到三级缓存中去创建B对象,B对象在创建时发现需要A对象,会先到一级缓存去找,没有去找二级缓存,还是没有,再去找三级缓存,找到了A,将A放入到二级缓存中,B创建完成,将自己放入一级缓存中,这是的A还没有创建完成,继续创建A,会直接到一级缓存中找到B,然后A也创建完成。  ​		那还有一个是使用@Lazy  注解解决玄幻依赖 他的底层是代理的方式实现的## **那pojo为啥还要自己==new==?**因为一般交给spring管理的对象,他的参数不能变化很多。POJO如果交给Spring管理,那么他的可变属性该怎么设置参数呢。## ==单例模式保证线程安全==双重检查锁 : 用volatile和synchronized来满足双重检查锁机制;## **==controller 这个Bean 是单例的还是多列 ?==**默认是单例 (这个对象有且仅有一个)。**==单例bean 存在什么问题==** 线程不安全    因为如果单例Bean 出现共享变量(成员属性) ,那么就会导致这个共享属性不安全。**如何解决呢?**1. 使用一个ThreadLocal这个类来进行线程绑定。
2. 可以是用线程安全的类
3. 修改的bean的作用域## ==单例bean 和 多例Bean 的生命周期==是怎么样的?单例Bean  :  容器生,Bean 就创建,,容器结束,Bean就死亡
多例Bean  :  用户调用的时候生 ,GC回收。    ## ==为什么Spring 不解决单列Bean线程不安全问题这个问题呢?==1.在开发的习惯中,Bean 中就不会存放成员属性(共享属性)   
2.可以使用多例来解决共享属性不安全的问题。
3.从性能上考虑,spring 选择了单例的方式。如果一定需要存在共享属性,那么可以通过@Scope("protype") 来修改他的Bean 类型。
4.spring 其实已经屏蔽掉了很多线程不安全的问题。spring内部,他使用的存储Bean的容器,是一个ThreadLocalMap注入配置类或者 Bean 对象,这个在 Spring Boot 里面的自动装配机制里面有用到。以上就是我对这个问题的理解。## Spring==设计模式==一、**单例模式**Bean默认是单例模式,这样有利于容器对bean的管理。**二、工厂模式**Spring容器本质是一个大工厂,使用工厂模式通过BeanFactory、ApplicationContext创建bean对象。**三、代理模式**Spring的AOP功能用到了JDK的动态代理和GGLIB字节码生成技术**四、模板模式**用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate**五、观察者模式**定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现–ApplicationListener## Spring 中 BeanFactory 和FactoryBean 的区别​      关于这个问题,我从几个方面来回答。​     首先,Spring 里面的核心功能是 IOC 容器,所谓 IOC 容器呢,本质上就是一个Bean 的容器或者是一个 Bean 的工厂。它能够根据 xml 里面声明的 Bean 配置进行 bean 的加载和初始化, 然后BeanFactory 来生产我们需要的各种各样的 Bean。所以我对 BeanFactory 的理解了有两个。BeanFactory 是所有 Spring Bean 容器的顶级接口,它为 Spring 的容器定义了一套规范,并提供像 getBean 这样的方法从容器中获取指定的 Bean 实例。BeanFactory 在产生 Bean 的同时,还提供了解决 Bean 之间的依赖注入的能力, 也就是所谓的 DI。FactoryBean 是一个工厂 Bean,它是一个接口,主要的功能是动态生成某一个类型的 Bean 的实例,也就是说,我们可以自定义一个 Bean 并且加载到 IOC 容器里面。它里面有一个重要的方法叫 getObject() ,这个方法里面就是用来实现动态构建Bean 的过程。Spring Cloud 里面的 OpenFeign 组件, 客户端的代理类, 就是使用了FactoryBean 来实现的。​       以上就是我对这个问题的理解。## ==@Resource 和 @Autowired 的区别==@Resource和@Autowired都是做bean的注入时使用,
其实@Resource并不是Spring的注解,它的包是javax.annotation.Resource,需要导入,但是Spring支持该注解的注入。1、共同点:两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法。
2,不同点:@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用,如下:Java代码@Autowired() @Qualifier("baseDao")private BaseDao baseDao;@Autowired() @Qualifier("baseDao") private BaseDao baseDao;@Resource(这个注解属于J2EE的),默认安装名称进行装配,名称可以通过name属性进行指定,
如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。
当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。# ==SpringBoot== 框架 (本质spring)**SpringBoot是由Pivotal团队提供的全新框架,设计目的是用来简化Spring应用的初始搭建以及开发过程**## ==配置文件级别==application.yml   application.properties  application.yaml针对程序启动的时候可能会用到的信息,一般配置与软件程序相关的bootstrap.yml  应用:配置nacos配置中心   启动配置文件  项目启动就会加载,优先级大于前三个,一般用作与系统类型的配置文件,针对于整个程序、**springboot内置的==日志框架==**log-back框架## ==常用注解(分层)==**`@SpringBootApplication`**:它也是 Spring Boot 的核心注解,主要组合包含了以下 3 个注解:**`@SpringBootConfiguration`**:组合了 @Configuration 注解,实现配置文件的功能,代表这个类是spring的配置类。**`@EnableAutoConfiguration`**:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置功能: ​			扫描所有Meta-inf 下的spring.factories文件 (一些全限定类名)**`@ComponentScan`**:Spring组件扫描,扫描spring注解放到IOC容器  。   基于servlet3.0  SPI机制## springboot==加载配置类的流程(自动装配)==首先启动springboot的启动类时,第一步会在底层创建一个ioc容器,其次第二步开始加载springboot的源配置类,也就是我们的启动类,第三步springboot会找到所有的配置类,然后在启动类上有个注解springbootapplication,在当前的这个注解中有三个注解有关,第一个是@CompomentScan,这个注解会扫描启动类所在包下的所有组件,第二个是springbootconfiguration,第三个是Enableautoconfiguration,它的作用是开启了自动配置的功能,这个注解里有一个import注解,在import注解中会导入一个autoconfigurationselector来实现自动配置,在这个selector中存在一个方法,这个方法中有一个方法叫loadfactoriesname,这个方法会返回一个类的名称叫Enableautoconfiguration,当检测到这个类的名称后会去配置文件中读取这个类的名字,也就是jar包中meta-info的spring.factories,这个文件是以key-value的形式创建的,key就是Enableautoconfiguration,在spring.factories里也有一个Enableautoconfiguration,当识别到这个时候,就可以把这个文件中所有的value值取出来,取出来之后就完成了自动装配的过程。## SpringBoot 的==约定优于配置==,你的理解是什么?我从 4 个点方面来回答。首先,约定优于配置是一种软件设计的范式,它的核心思想是减少软件开发人员对于配置项的维护,从而让开发人员更加聚焦在业务逻辑上。Spring Boot 就是约定优于配置这一理念下的产物,它类似于 Spring 框架下的一个脚手架,通过 Spring Boot,我们可以快速开发基于 Spring 生态下的应用程序。基于传统的 Spring 框架开发 web 应用,我们需要做很多和业务开发无关并且只需要做一次的配置,比如管理 jar 包依赖 web.xml 维护Dispatch-Servlet.xml 配置项维护应用部署到 Web 容器,第三方组件集成到 Spring IOC 容器中的配置项维护,而在 Spring Boot 中,我们不需要再去做这些繁琐的配置,Spring Boot 已经自动帮我们完成了,这就是约定由于配置思想的体现。Spring Boot 约定由于配置的体现有很多,比如:Spring Boot Starter 启动依赖,它能帮我们管理所有 jar 包版本,如果当前应用依赖了spring mvc 相关的jar,那么Spring Boot会自动内置Tomcat,容器来运行 web 应用,我们不需要再去单独做应用部署。Spring Boot 的自动装配机制的实现中,通过扫描约定路径下的 spring.factories,文件来识别配置类,实现 Bean 的自动装配。默认加载的配置文件 application.properties 等等。总的来说,约定优于配置是一个比较常见的软件设计思想,它的核心本质都是为了更高效以及更便捷的实现软件系统的开发和维护。以上就是我对这个问题的理解。### 如何理解 **Spring** **Boot** 中的 ==Starter==?Starter 是 Spring Boot 的四大核心功能特性之一,除此之外,Spring Boot 还有自动装配、Actuator 监控等特性。Spring Boot 里面的这些特性,都是为了让开发者在开发基于 Spring 生态下的企业级应用时,只需要关心业务逻辑,减少对配置和外部环境的依赖。其中,Starter 是启动依赖,它的主要作用有几个。Starter 组件以功能为纬度,来维护对应的 jar 包的版本依赖,使得开发者可以不需要去关心这些版本冲突这种容易出错的细节。Starter 组件会把对应功能的所有 jar 包依赖全部导入进来,避免了开发者自己去引入依赖带来的麻烦。Starter 内部集成了自动装配的机制,也就说在程序中依赖对应的 starter 组件以后,这个组件自动会集成到 Spring 生态下,并且对于相关 Bean 的管理,也是基于自动装配机制来完成。依赖 Starter 组件后,这个组件对应的功能所需要维护的外部化配置,会自动集成到 Spring Boot 里面,我们只需要在 application.properties 文件里面进行维护就行了,比如 Redis 这个starter,只需要在 application.properties文件里面添加 redis 的连接信息就可以直接使用了。在我看来,Starter 组件几乎完美的体现了Spring Boot 里面约定优于配置的理念。另外,Spring Boot 官方提供了很多的 Starter 组件,比如 Redis、JPA、MongoDB等等。但是官方并不一定维护了所有中间件的 Starter,所以对于不存在的 Starter,第三方组件一般会自己去维护一个。官方的 starter 和第三方的 starter 组件,最大的区别在于命名上。官方维护的 starter 的以 spring-boot-starter 开头的前缀。第三方维护的 starter 是以 spring-boot-starter 结尾的后缀这也是一种约定优于配置的体现。以上就是我对这个问题的理解。### springboot==怎么实现异步?==**@Async**的作用就是异步处理任务。在方法上添加@Async,表示此方法是异步方法;
在类上添加@Async,表示类中的所有方法都是异步方法;
使用此注解的类,必须是Spring管理的类;
需要在启动类或配置类中加入@EnableAsync注解,@Async才会生效;
在使用@Async时,如果不指定线程池的名称,也就是不自定义线程池,@Async是有默认线程池的,使用的是Spring默认的线程池SimpleAsyncTaskExecutor。默认线程池的默认配置如下:默认核心线程数:8;
最大线程数:Integet.MAX_VALUE;
队列使用LinkedBlockingQueue;
容量是:Integet.MAX_VALUE;
空闲线程保留时间:60s;
线程池拒绝策略:AbortPolicy;使用`@Async`注解,从最大线程数可以看出,在并发情况下,每次调用都会新建一条线程。所以使用Spring中的@Async异步框架时一定要自定义线程池;**ThreadPoolTaskExecutor**创建了一个线程池,同时设置了以下这些参数:核心线程数10:线程池创建时候初始化的线程数
最大线程数20:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
缓冲队列200:用来缓冲执行任务的队列
允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务### 核心线程数Runtime.getRuntime().availableProcessors()获取的是CPU核心线程数,也就是计算资源。CPU密集型,线程池大小设置为N,也就是和cpu的线程数相同,可以尽可能地避免线程间上下文切换,但在实际开发中,一般会设置为N+1,为了防止意外情况出现线程阻塞,如果出现阻塞,多出来的线程会继续执行任务,保证CPU的利用效率。
IO密集型,线程池大小设置为2N,这个数是根据业务压测出来的,如果不涉及业务就使用推荐。
在实际中,需要对具体的线程池大小进行调整,可以通过压测及机器设备现状,进行调整大小。
如果线程池太大,则会造成CPU不断的切换,对整个系统性能也不会有太大的提升,反而会导致系统缓慢。### ==@Async失效==的几个原因注解@Async的方法不是public方法;
注解@Async的返回值只能为void或Future;
注解@Async方法使用static修饰也会失效;
没加@EnableAsync注解;
调用方和@Async不能在一个类中;
在Async方法上标注@Transactional是没用的,但在Async方法调用的方法上标注@Transcational是有效的;### SpringBoot==读取配置文件==的三种方法①Environment是用来读取应用程序运行时的[环境变量](https://so.csdn.net/so/search?q=环境变量&spm=1001.2101.3001.7020)的类,可以通过key-value的方式读取application.properties和系统环境变量,命令行输入参数,系统属性等②使用[@Value](https://github.com/Value)注解读取配置文件内容,其实[@Value](https://github.com/Value)底层就是Environment.java③使用[@ConfigurationProperties](https://github.com/ConfigurationProperties)首先建立配置文件与对象的映射关系,然后在控制器方法中使用[@Autowired](https://github.com/Autowired)注解将对象注入,定义属性配置类和属性类# **==springMVC==**框架SpringMVC是一种基于Java实现MVC模型的轻量级Web框架.**相当于servlet,灵活性强**SpringMVC就是让我们编写controller请求,处理请求,将结果解析成json相应给前端.### 说说你对 **Spring** **MVC** 的理解好的,关于这个问题,我会从几个方面来回答。首先,Spring MVC 是是属于 Spring Framework 生态里面的一个模块,它是在Servlet 基础上构建并且使用 MVC 模式设计的一个 Web 框架, 主要的目的是简化传统 Servlet+JSP 模式下的 Web 开发方式。其次,Spring MVC 的整体架构设计对 Java Web 里面的 MVC 架构模式做了增强和扩展,主要有几个方面。把传统 MVC 框架里面的 Controller 控制器做了拆分, 分成了前端控制器DispatcherServlet 和后端控制器 Controller。把 Model 模型拆分成业务层 Service 和数据访问层 Repository。在视图层,可以支持不同的视图,比如 Freemark、velocity、JSP 等等。所以,Spring MVC 天生就是为了 MVC 模式而设计的,因此在开发 MVC 应用的时候会更加方便和灵活。Spring MVC 的具体工作流程是,浏览器的请求首先会经过 SpringMVC 里面的核心控制器 DispatcherServlet,它负责对请求进行分发到对应的 Controller。Controller 里面处理完业务逻辑之后,返回 ModeAndView。然后 DispatcherServlet 寻找一个或者多个 ViewResolver 视图解析器,找到ModeAndView 指定的视图,并把数据显示到客户端。以上就是我对 Spring MVC 的理解。### ==多线程存在问题:==1、线程的生命周期开销非常高2、消耗过多的 CPU
资源如果可运行的线程数量多于可用处理器的数量,那么有线程将会被闲置。大量空闲的线程会占用许多内存,给垃圾回收器带来压力,而且大量的线程在竞争 CPU资源时还将产生其他性能的开销。3、降低稳定性JVM
在可创建线程的数量上存在一个限制,这个限制值将随着平台的不同而不同,并且承受着多个因素制约,包括 JVM 的启动参数、Thread 构造函数中请求栈的大小,以及底层操作系统对线程的限制等。如果破坏了这些限制,那么可能抛出OutOfMemoryError 异常。### ==常用注解==**`@Controller注解`**:设定SpringMVC的核心控制器bean   代表此类是一个处理类**`@RequestMapping注解`**:设置当前控制器方法请求访问路径   请求路径映射@GetMapping  @PostMapping @DeleteMapping @PutMapping 	**`@ResponseBody注解`**:将controller层方法的返回值解析成json返回@RequestBody 请求转JSON  @PathValuxxxx   @RequestParam**`@ControllerAdvice`**:(全局异常处理器)   **`@RequestHeader`** :获得请求头@ExceptionHandler### ==核心组件:==前端控制器 用于接收响应请求处理器映射器  找到处理请求得contriller处理器适配器  找到执行请求的方法适配器  执行方法的视图解析器  进行页面跳转多媒体解析器 上传文件### ==拦截器==拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行.- 实现HandlerInterceptor接口过滤器(Filter)属于Servlet技术### 拦截器和过滤器的==区别==:①拦截器是基于java的反射机制的,而过滤器是基于函数回调。②拦截器不依赖与servlet容器,过滤器依赖与servlet容器。③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。④拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。⑤在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。⑥拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。拦截器可以获取ioc中的service bean实现业务逻辑。### **==父子容器关系:==**1.父容器不可以访问子容器的任何Bean  2.子容器可以访问父容器的任何Bean### **springMVC==处理器:==**1.处理器映射器(HandlerMapping)  2.前端控制器(dispatcherServlet) 3.处理器适配器(handlerAdapter) 4.视图解析器(viewResolver)### **springmvc==参数注解:==**1.`@RequestBody`(请求体入参JSON)   2.`@RequestParam` 普通参数入参    3.`@PathVariable`(请求URL入参RestFul)### **springmvc==常用注解:==**1.@RestController   2.@GetMapping("/test")一类注解    3.@ResponseBody   4.@ControllerAdvice(全局异常处理器)   5.@RequestHeader 获得请求头    6.@SessionAttribute### **springmvc==执行流程:==**1.用户发送请求到`前端控制器(dispatcherservlet)`2.前端控制器转发给`处理映射器(handlerMapping)`3.处理器映射器找到处理器请求的Controller 4.转交给dispatcherservlet ,再由dispatcherservlet转交给`处理器适配器(HandlerAdapter)`5.处理器适配器,找到处理请求的适配器,交由适配器执行此请求。6.返回`ModelAndView对象` 返回给`前端控制器。`7.再由前端控制器,转交给`视图解析器(viewReslover)`,8.由视图解析器,根据Model 和 VIEW 解析获得真正的物理视图,然后`渲染`转发给前端控制器9.由前端控制器响应给用户### **springmvc实现==重定向和转发:==**1.转发 forward:/index.html    2.重定向 redirect:/index.html### **==用户发送请求到后端,怎么执行的?==**         1.访问域名解析服务器,把**域名解析成服务器IP地址**
2.通过IP地址,找到互联网服务器地址,(访问网关)
3.**网关进行请求的路由转发 >> 处理请求微服务**4.用户和服务器**创建连接**  --》3次握手 --》1.请求连接,2.同意连接   3.创建连接5.微服务返回数据给用户6.用户**请求结束** -->**四次挥手** -->1.请求断开  2.等待后置处理(收尾工作) 3.同意断开   4.断开**Spring Data JPA :** 要了解一下# **==SpringCloud==框架**### 关于你对==Spring Cloud的理解==Spring Cloud 是一套分布式微服务的技术解决方案,它提供了快速构建分布式系统的常用的一些组件比如说 **配置管理、服务的注册与发现、服务调用的负载均衡、资源隔离、熔断降级**等等不过 Spring Cloud 只是 Spring 官方提供的一套微服务标准定义而真正的实现目前有两套体系用的比较多一个是 Spring Cloud Netflix一个是 Spring Cloud AlibabaSpring Cloud Netflix 是基于 Netflix 这个公司的开源组件集成的一套微服务解决方案,其中的组件有1. Ribbon——负载均衡 2. Hystrix——服务熔断3. Zuul——网关 4. Eureka——服务注册与发现 5. Feign——服务调用Spring Cloud **Alibaba** 是基于阿里巴巴开源组件集成的一套微服务解决方案,其中包括1. Dubbo——消息通讯 2. Nacos——服务注册与发现3.Seata——事务隔离 4. Sentinel——熔断降级有了 Spring Cloud 这样的技术生态使得我们在落地微服务架构时不用去考虑第三方技术集成带来额外成本 只要通过配置组件来完成架构下的技术问题从而可以让我们更加侧重性能方面以上这些就是我对 Spring Cloud 的个人理解! ### 微服务架构原理是什么主要是面向SOA理念,更细小粒度服务的拆分,将功能分解到各个服务当中,从而降低系统的耦合性,并提供更加灵活的服务支持。### **==五大核心组件==:** 配置管理(Spring Cloud Config、**Apollo**、nacos)**服务的注册与发现**(Netflix Eureka、 **Nacos** 、 Zookeeper)服务调用的**负载均衡**(Netflix Ribbon )**服务网关**(Netflix Zuul 、SpringCloud **Gateway**)**熔断降级**(Netflix **Hystrix** )服务接口调用 (Netflix Feign 、 **Openfeign**)### 各==组件的作用==:**注册中心:**我理解注册中心的作用就相当于是个中介,各个微服务把自己的信息注册到注册中心,比如说自己的ip地址端口号,方便各个微服务之间相互调用,假如消费者需要调用微服务,直接找nacos取,然后把提供者的地址缓存到本地,下次再调用的时候,直接从本地的服务列表中取,而且nacos作为注册中心也起到了一个解耦合的作用,因为微服务要想被其他微服务调用或者消费,它要把自己注册到nacos中心,假如有微服务挂了,它在nacos中的ip地址和端口号也会被清楚,其他微服务中它的信息也会被清除
**zookeeper和eureka做注册中心的区别**zookeeper保证的是cp也就是一致性,eureka保证的是ap也就是可用性,实际上做注册中心对一致性要求并不高
**配置中心**:配置中心就是字面意思,在微服务启动之前,把所有的配置信息从配置仓库拉取到配置中心,达到统一化配置管理的目的
**熔断器**:微服务中有许多微服务需要相互调用的,如果不做熔断保护的话,假如有一个微服务挂了,那么就会引起连锁反应,导致别的微服务也挂了,Hystrix是springcloud原生的熔断器,他是熔断,隔离以及降级的一个框架,好比说我现在调用一个微服务报错或者挂了,就对这个微服务熔断,5分钟内对这个服务请求直接返回个默认值,不需要每次都卡几秒,这个过程就是熔断实现原理就是 正常情况下熔断器是关闭的,但是当访问一个微服务一直失败,达到一个阈值,就会断开断路器,不再向服务提供者发起请求,断路器打开一段时间后,它会自动进入一个半开的状态,每次会放一点请求进来,看看是不是还是坏的,如果请求成功,那么关闭断路器,如果失败,继续保持断路器状态
**feign**feign的本质就是一个http的客户端,它的服务就是在两个微服务之间做一个远程调用,一个服务去调用另一个微服务的接口,就用到了feign
**ribbon**ribbon负载均衡,这个主要是搭建集群环境下,起到一个负载均衡的作用,假如说我现在有一个请求,但是我有两台服务器,这时候就可以通过ribbon的负载均衡策略,比如说轮询啊,随机啊,权重,去分配到其中一台服务器,来保证系统的高可用
**gateway**网关是作为整个系统的一个出入口,用户发来请求会经过网关进行一个统一的处理,比如说鉴权,跨域处理,日志记录等,获取到响应结果,也会经过网关返回给用户### ==Nacos服务注册与发现==nacos是阿里开源的产品,他是针对非服务、配置管理、服务治理的综合性解决方法。**描述**: 微服务在启动后会向nacos进行注册, nacos server 会将注册信息向其他 nacos server 进行同步,当服务消费者要调用服务的提供者,则向服务注册中心获取服务提供者地址,然后会将服务提供者地址缓存在本地,下次再调用时,则直接从本地缓存中获取服务列表来完成服务调用服务注册与发现过程:`服务注册中心`(Nacos)、`服务提供者`(provider)、`服务消费者`(consumer)1. 服务容器负责启动,加载`bootstrap.yaml文件`,获取nacos地址、配置文件id;读取nacos配置文件,运行服务提供者。2. 服务提供者在启动时,向注册中心注册自己提供的服务。3. 服务消费者在启动时,向注册中心订阅自己所需的服务。4. **注册中心返回服务提供者地址列表**给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。(服务降级)6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。### **Nacos** 配置更新的==工作流程==好的,面试官,这个问题我需要从几个方面来回答。首先,Nacos 是采用长轮训的方式向 Nacos Server 端发起配置更新查询的功能。所谓长轮训就是客户端发起一次轮训请求到服务端,当服务端配置没有任何变更的时候,这个连接一直打开。直到服务端有配置或者连接超时后返回。Nacos Client 端需要获取服务端变更的配置,前提是要有一个比较,也就是拿客户端本地的配置信息和服务端的配置信息进行比较。一旦发现和服务端的配置有差异,就表示服务端配置有更新,于是把更新的配置拉到本地。在这个过程中,有可能因为客户端配置比较多,导致比较的时间较长,使得配置同步较慢的问题。于是 Nacos 针对这个场景,做了两个方面的优化。减少网络通信的数据量,客户端把需要进行比较的配置进行分片,每一个分片大小是 3000,也就是说,每次最多拿 3000 个配置去 Nacos Server 端进行比较。分阶段进行比较和更新;第一阶段,客户端把这 3000 个配置的 key 以及对应的 value 值的 md5 拼接成一个字符串,然后发送到 Nacos Server 端进行判断,服务端会逐个比较这些配置中 md5 不同的 key,把存在更新的 key 返回给客户端。第二阶段,客户端拿到这些变更的 key,循环逐个去调用服务单获取这些 key 的value 值。这两个优化,核心目的是减少网络通信数据包的大小,把一次大的数据包通信拆分成了多次小的数据包通信。虽然会增加网络通信次数,但是对整体的性能有较大的提升。最后,再采用长连接这种方式,既减少了 pull 轮询次数,又利用了长连接的优势, 很好的实现了配置的动态更新同步功能。以上就是我对这个问题的理解。### ==负载均衡==关于负载均衡,我会从四个方面去说。1. 负载均衡产生的背景2. 负载均衡的实现技术3. 负载均衡的作用范围4. 负载均衡的常用算法负载均衡的诞生背景在互联网发展早期,由于用户量较少、业务需求也比较简单。对于软件应用,我们只需要一台高配的服务器即可完成业务的支撑,这样的软件架构称为单体架构随着用户量的增加,服务器的请流量也随之增加,在这个过程中单体架构会产生两个问题。1. 软件的性能逐步下降,访问延迟越来越高2. 容易出现单点故障为了解决这个问题,我们引入了集群化部署的架构,也就是把一个软件应用同时部署在多个服务器上### **熔断降级(Hystrix)**#### 吹牛逼部分Hystrix设计目标:
对来自依赖的延迟和故障进行防护和控制——这些依赖通常都是通过网络访问的
阻止故障的连锁反应
快速失败并迅速恢复
回退并优雅降级
提供近实时的监控与告警Hystrix遵循的设计原则:
防止任何单独的依赖耗尽资源(线程)
过载立即切断并快速失败,防止排队
尽可能提供回退以保护用户免受故障
使用隔离技术(例如隔板,泳道和断路器模式)来限制任何一个依赖的影响
通过近实时的指标,监控和告警,确保故障被及时发现
通过动态修改配置属性,确保故障及时恢复
防止整个依赖客户端执行失败,而不仅仅是网络通信Hystrix如何实现这些设计目标?
使用命令模式将所有对外部服务(或依赖关系)的调用包装在HystrixCommand或HystrixObservableCommand对象中,并将该对象放在单独的线程中执行;
每个依赖都维护着一个线程池(或信号量),线程池被耗尽则拒绝请求(而不是让请求排队)。
记录请求成功,失败,超时和线程拒绝。
服务错误百分比超过了阈值,熔断器开关自动打开,一段时间内停止对该服务的所有请求。
请求失败,被拒绝,超时或熔断时执行降级逻辑
近实时地监控指标和配置的修改#### 精华在此hystrix是什么?Netflix的 Hystrix 是一个帮助解决分布式系统交互时超时处理和容错的类库, 它同样拥有保护系统的能力.==Hystrix的设计原则包括:资源隔离、熔断器、命令模式。====资源隔离==货船为了进行防止漏水和火灾的扩散,会将货仓分隔为多个,这种资源隔离减少风险的方式被称为:Bulkheads(舱壁隔离模式)。Hystrix将同样的模式运用到了服务调用者上,在一个高度服务化的系统中,一个业务逻辑通常会依赖多个服务,比如:商品详情展示服务会依赖商品服务,价格服务,商品评论服务。调用三个依赖服务会共享商品详情服务的线程池。如果其中的商品评论服务不可用,就会出现线程池里所有线程都因等待响应而被阻塞,从而造成服务雪崩。Hystrix通过将每个依赖服务分配独立的线程池进行资源隔离,从而避免服务雪崩。==熔断器模式==熔断器模式定义了熔断器开关相互转换的逻辑。服务的健康状况 = 请求失败数 / 请求总数。熔断器开关由关闭到打开的状态转换是通过当前服务健康状况和设定阈值比较决定的。当熔断器开关关闭时,请求被允许通过熔断器。 如果当前健康状况高于设定阈值,开关继续保持关闭。如果当前健康状况低于设定阈值,开关则切换为打开状态。当熔断器开关打开时,请求被禁止通过。当熔断器开关处于打开状态,经过一段时间后,熔断器会自动进入半开状态,这时熔断器只允许一个请求通过。当该请求调用成功时,熔断器恢复到关闭状态。若该请求失败,熔断器继续保持打开状态,接下来的请求被禁止通过。熔断器的开关能保证服务调用者在调用异常服务时,快速返回结果,避免大量的同步等待,并且熔断器能在一段时间后继续侦测请求执行结果,提供恢复服务调用的可能。
==回退降级==
降级,通常指务高峰期,为了保证核心服务正常运行,需要停掉一些不太重要的业务,或者某些服务不可用时,执行备用逻辑从故障服务中快速失败或快速返回,以保障主体业务不受影响。Hystrix提供的降级主要是为了容错,保证当前服务不受依赖服务故障的影响,从而提高服务的健壮性。要支持回退或降级处理,可以重写HystrixCommand的getFallBack方法或HystrixObservableCommand的resumeWithFallback方法。==命令模式==Hystrix使用命令模式(继承HystrixCommand类)来包裹具体的服务调用逻辑(run方法),并在命令模式中添加了服务调用失败后的降级逻辑(getFallback)。同时在Command的构造方法中可以定义当前服务线程池和熔断器的相关参数。因此在使用了Command模式构建了服务对象之后,服务便拥有了熔断器和线程池的功能。Hystrix容错(特点+)资源隔离线程池和信号量
熔断
降级Hystrix Dashboardpom.xml<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>配置文件:```xml
feign.hystrix.enabled=true
management.endpoints.web.exposure.include=hystrix.stream#超时时间,默认1000,单位ms。
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=100000
#线程池核心线程数,最多同时只有2个线程在执行
hystrix.threadpool.default.coreSize=2
#线程池最大队列数,也可以理解为最多只能添加4个请求进来。包括正在执行的请求。
hystrix.threadpool.default.maxQueueSize=4
#线程池最大线程数。最多只能接收2+3=5个线程数。
hystrix.threadpool.default.maximumSize=3
#队列拒绝阈值,即使队列数没有达到maxQueueSize,也会拒绝接收任务
hystrix.threadpool.default.queueSizeRejectionThreshold=6
#一个rolling window内最小的请求数。如果请求数少于该值,则不论如何也不会触发短路。
hystrix.command.default.circuitBreaker.requestVolumeThreshold=3
#错误率阈值。如果一个rolling window内的请求错误率超过了该值,则会开启熔断器
hystrix.command.default.circuitBreaker.errorThresholdPercentage=0.5
#触发短路的时间值,单位毫秒。
hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=5000

启动类上加
@EnableHystrixDashboard
@EnableCircuitBreaker

   @Bean
public ServletRegistrationBean getServlet() {HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);registrationBean.setLoadOnStartup(1);registrationBean.addUrlMappings("/hystrix.stream");registrationBean.setName("HystrixMetricsStreamServlet");return registrationBean;
}

启动访问localhost:8094/hystrix

雪花算法生成的id由哪些部分组成?

1.符号位,占用1位。

2.时间戳,占用41位,可以支持69年的时间跨度。

3.机器id,占用10位。

4.序列号,占用12位,一毫秒可以生成4095个id


http://www.xdnf.cn/news/1068553.html

相关文章:

  • TensorFlow Lite (TFLite) 和 PyTorch Mobile模型介绍1
  • 什么是功能测试和非功能测试?
  • Azure 托管 Redis 已正式发布
  • 打造属于你的AI智能体,从数据开始 —— 使用 Bright Data MCP+Trae快速构建垂直智能体
  • 【Elasticsearch】es初识,在项目架构中的用途,与mysql和kafka的配合使用,
  • linux安装docker
  • LE AUDIO---Chapter 2. The Bluetooth® LE Audio architecture
  • 记一次AWS 中RDS优化费用使用的案例
  • 【学习笔记】3.3 Decoder-Only PLM
  • 【目标检测】平均精度(AP)与均值平均精度(mAP)计算详解
  • 从数据到决策:UI前端如何利用数字孪生技术提升管理效率?
  • list的使用和模拟实现
  • 探索解析C++ STL中的 list:双向链表的高效实现与迭代器
  • Flutter MobX 响应式原理与实战详解
  • OpenLayers 上传Shapefile文件
  • docker start mysql失败,解决方案
  • 【猜你需要】使用了Git LFS还是无法上传文件?文件过大?
  • 打造丝滑的Android应用:LiveData完全教程
  • 【启发式算法】RRT*算法详细介绍(Python)
  • Oracle 数据库查询:多表查询
  • 测试平台ui自动化demo说明
  • [论文阅读] 人工智能 + 软件工程 | 探秘LLM软件代理:从黑箱决策到透明轨迹分析
  • 创客匠人 AI 赋能:创始人 IP 打造的效率革命与信任重构
  • 数的范围(连续数字边界)
  • 以太网基础②RGMII 与 GMII 转换电路设计
  • Spring Boot 系统开发:打造高效、稳定、可扩展的企业级应用
  • 学习日记-spring-day37-6.25
  • SpringCloud系列(35)--使用HystrixDashboard进行服务监控
  • OSS跨区域复制灾备方案:华东1到华南1的数据同步与故障切换演练
  • 数智时代如何构建人才培养生态?生成式人工智能(GAI)认证,引领数智时代人才培养新方向