spring和springboot和springcloud专题

  1. Spring框架是J2EE编程领域的一个轻量级开源框架,是针对bean的生命周期进行管理的轻量级容器;依赖注入IOC和面向切面编程AOP是Spring的灵魂;常见的配置方式:XML配置、注解配置、Java配置。

    Spring的几个核心模块:

    • Spring Core:核心类库,提供IOC服务
    • Spring Context:提供框架式的Bean访问方式,以及企业级功能
    • Spring AOP:AOP服务
    • Spring DAO:对JDBC的抽象,简化了数据访问异常的处理
    • Spring ORM:对现有的ORM框架的支持
    • Spring WEB:提供了基本的面向WEB的综合特性,如文件上传
    • Spring MVC:提供面向WEB应用的Model-View-Controller实现
  2. Spring优点

    • 属于低侵入式设计,IOC机制将对象之间的依赖关系交由框架处理,减少组件耦合性
    • AOP技术支持将一些通用任务,如安全、事务、日志、权限等进行集中式管理,从而更好地实现复用
    • 主流的应用框架提供了集成支持,主流的ORM框架,如mybatis/struct/hibernate等
  3. Spring的IOC和AOP机制:

    • IOC:控制反转(依赖注入),利用工厂模式将对象交给容器管理,spring容器启动时会将配置文件中的bean都初始化好,使用的时候,只要将被使用的bean注入到调用方类中即可,不需要再new被调用者对象;
    • AOP:将程序中的交叉业务逻辑(例如安全日志事务),封装成一个切面,注入到目标对象中去;可以减少系统中的重复代码,降低了模块间的耦合度,同时提高了系统的可维护性;可用于权限认证、日志、事务处理。
  4. Spring的几种注入方式:

    • 属性注入:使用@Autowired(Spring注解)、@Resource(JAVA注解)都可实现注入
      • @Autowired按照type注入,如果存在多个,则按照name匹配(按照@Qualifier指定的name或者变量名);
      • @Resource如果同时指定了nametype,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常;如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常;如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或是找到多个,都会抛出异常;如果既没有指定name,又没有指定type,则默认按照byName方式进行装配;如果没有匹配,按照byType进行装配
    • set方法注入:灵活,可以选择性的注入对象,prototype模式下会存在循环依赖问题,抛异常;singleton模式下spring会通过二级缓存和三级缓存自动处理掉
    • 构造方法注入:不够灵活,当需要注入多个对象时,构造器参数列表很长,或者需要多个重载构造器,存在循环依赖问题,抛异常
  5. AOP代理模式:分为静态代理和动态代理,区别在于生成AOP代理对象的时机不同

    • 静态代理的代表为AspectJ:所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强;会在编译阶段将AspectJ(切面)织入到Java字节码中,运行时候就是增强之后的AOP对象;设计模式里边的案例就是静态代理,在编译期间会将接口、实现类和代理类编译成class文件
    • Spring AOP使用的是动态代理:所谓动态代理,就是AOP框架在每次运行时在内存中临时为方法生成一个AOP对象,这个对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法;
  6. Spring的动态代理主要有两种方式:JDK动态代理和CGLIB动态代理

    1. JDK动态代理只提供接口的代理,不支持类的代理;核心InvocationHandler接口和Proxy类

    2. 如果代理类没有实现InvocationHandler接口,那么SpringAOP会选择使用CGLIB来动态代理目标类;可以在运行时动态生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP;CGLIB是通过继承的方式做的动态代理,因此无法动态代理某个被final标记的类。

  7. Spring AOP几个概念

    • 连接点:指程序运行过程中所执行的方法
    • 切面:被抽取出来的公共模块,在Spring AOP中,切面可以在类上使用 @AspectJ 注解来实现
    • 切点:切点用于定义要对哪些连接点进行拦截,切点分为execution方式和annotation方式;execution方式可以用路径表达式指定对哪些方法拦截,比如指定拦截add*、search*;annotation方式可以指定被哪些注解修饰的代码进行拦截
    • 通知:指要在连接点上执行的动作,即增强的逻辑;通知有各种类型,包括Around、Before、After、Around、After returning、After throwing
  8. 拦截器 VS 过滤器 VS Aspect

    • 先说明一下:AOP是一种技术、思想,而Aspect、拦截器和过滤器是AOP技术、思想的具体实现;Aspect是针对具体的方法进行增强;而拦截器主要是针对Controller接口进行拦截

    • 来源:过滤器来自于java的servlet包;拦截器来自于Spring框架

    • 触发时机:请求进入容器 -> 过滤器 -> Servlet -> 拦截器 -> 执行控制器(Controller)

    • 实现原理:

      • 过滤器是基于方法回调实现的:doFilter方法中,我们要执行下一个过滤器或者流程时,需调用FilterChain对象的doFilter方法进行回调执行
      • 拦截器是基于动态代理(底层是反射)实现的:代理目标Controller
    • 支持项目类型:

      • 过滤器是依赖于Servlet容器的,只能用于WEB项目
      • 拦截器是Spring的组件,可以应用在WEB、APPLICATION中
    • 使用场景:

      • 拦截器更接近于业务系统,主要用来实现项目中业务判断,比如:登录校验权限判断日志记录
      • 过滤器通常用来实现通用功能的过滤,比如:敏感词过滤字符编码集设置、响应数据压缩等
  9. BeanFactory和ApplicationContext有什么区别

    • BeanFactory是Spring里面最底层的接口,是IoC的核心,定义了IoC的基本功能,包含了各种Bean的定义、加载、实例化,依赖注入和生命周期管理
    • ApplicationContext接口作为BeanFactory的子类,还提供了国际化支持、资源文件访问
    • BeanFactroy采用的是延迟加载形式来注入Bean的,只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化;ApplicationContext是在容器启动时,一次性创建了所有的Bean
  10. Bean的生命周期:实例化->属性赋值->初始化->销毁

    • 实例化Bean对象:通过BeanFactory/ApplicationContext容器实例化Bean

    • 设置对象属性(依赖注入):Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成属性设置与依赖注入

    • 处理Aware接口:我们的Bean实现Spring的某些容器Aware接口,为了利用这些容器对象提供的能力/服务

      • BeanNameAware接口:会调用它实现的setBeanName(String beanId)方法,传入Bean的名字
      • BeanClassLoaderAware接口:调用setBeanClassLoader()方法,传入ClassLoader对象的实例
      • BeanFactoryAware接口:会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身
      • ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文
    • BeanPostProcessor前置处理:如果想对Bean进行一些自定义的前置处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法

    • InitializingBean:如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法

    • init-method:如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法

    • BeanPostProcessor后置处理:如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术

    • DisposableBean:当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法

    • destroy-method:最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法

  11. @PostConstruct注解

    • Java自己的注解,被用来修饰非静态void方法
    • 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次
    • PostConstruct在构造函数之后执行,init()方法之前执行
    • PostConstruct方法在Bean初始化过程中的顺序:Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)
  12. bean的作用域

    • singleton:默认单例
    • prototype:每一个bean请求创建一个实例
    • request:为每一个request请求创建一个实例
    • session:类似request,同一个session会话共享一个实例
    • global-session:全局作用域,所有会话共享一个实例
  13. spring中的bean线程安全吗?

    • Spring容器本身并没有提供Bean的线程安全策略,因此可以说Spring容器中的Bean本身不具备线程安全的特性
    • 对于prototype作用域的Bean,每次都创建一个新对象,也就是线程之间不存在Bean共享,因此不会有线程安全问题
    • 对于singleton作用域的Bean,所有的线程都共享一个单例实例的Bean,因此是存在线程安全问题的;但是如果单例Bean是一个无状态Bean,也就是线程中的操作不会对Bean的成员执行查询以外的操作,那么这个单例Bean是线程安全的。比如Controller类、Service类和Dao等,这些Bean大多是无状态的,只关注于方法本身
  14. spring如何处理线程并发问题?

    • ThreadLocal:空间换时间,为每一个线程提供独立副本隔离多个线程对数据的访问冲突;
    • 同步机制:时间换空间,多个线程在访问同一份数据时,需要获取
  15. spring中的一些设计模式

    • 工厂模式:Spring使用工厂模式,通过BeanFactory和ApplicationContext来创建对象
    • 单例模式:Bean默认为单例模式
    • 代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术
    • 策略模式:例如Resource的实现类,针对不同的资源文件,实现了不同方式的资源获取策略
  16. springmvc

    • 对springmvc的理解:

      • 基于Java实现了MVC设计模式的请求驱动类型的轻量级Web框架;
      • 通过Model、View、Controller分离,将web层进行职责解耦,纵向分层,简化开发
    • springmvc的主要组件:

      • 前端控制器DispatcherServlet:接收请求、响应结果,相当于转发器
      • 处理器映射器HandlerMapping:根据请求的URL来查找Handler
      • 处理器适配器HandlerAdapter:执行具体Handler
      • 处理器Handler:程序员开发,处理具体web逻辑
      • 视图解析器ViewResolver:进行视图解析,根据试图逻辑名解析成真正的视图
      • 视图View:程序员开发的jsp
    • springmvc注解:

      • @RequestMapping:用于处理请求url, 把web请求映射到相应的处理函数
      • @RequestBody:实现接收http请求的json数据,将json转为java
        • 原理:根据不同的content-type,spring-mvc会采用不同的消息转换器HttpMessageConverter进行数据解析;使用jackson转换器进行反序列化
      • @ResponseBody:实现将conreoller方法返回对象转化为json对象响应给客户
    • springmvc流程:核心是前端控制器DispatcherServlet

      • 用户发送请求至前端控制器DispatcherServlet
      • DispatcherServlet收到请求后,调用HandlerMapping处理器映射器,请求获取Handler
      • 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
      • DispatcherServlet 调用 HandlerAdapter处理器适配器,调用具体处理器
      • Handler执行完成返回ModelAndView;HandlerAdapter将Handler执行结果ModelAndView返回给DispatcherServlet
      • DispatcherServlet将ModelAndView传给ViewResolver视图解析器进行解析;ViewResolver解析后返回具体View
      • DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
  17. springboot有哪些优点?

    • 可快速构建独立的 Spring 应用

      • Spring Boot是一个依靠大量注解实现自动化配置的全新框架
      • 在构建Spring应用时,我们只需要添加相应的场景依赖,Spring Boot就会根据添加的场景依赖自动进行配置
    • 直接嵌入Tomcat、Jetty 和Undertow 服务器

    • 通过依赖starter启动器简化构建配置

      • 例如,在Web开发时,只需在构建项目时选择对应的Web场景依赖启动器spring-boot-starter-web
      • Spring Boot项目便会自动导入spring-webmvc、spring-web、spring-boot-starter-tomcat等子依赖,并自动下载和获取Web开发需要的相关JAR包
    • 自动化配置Spring和第三方库,简化了XML配置

      • 在提供了各种场景依赖启动器的基础上,内部还默认提供了各种自动化配置类
      • 使用Spring Boot开发项目时,一旦引入了某个场景的依赖启动器,Spring Boot内部提供的默认自动化配置类就会生效
    • 提供生产就绪功能

      • Spring Boot提供了一些用于生产环境运行时的特性,例如指标、监控检查和外部化配置
  18. springboot监视器是什么?

    • Spring boot actuator是spring启动框架中的重要功能之一
    • 可帮助访问生产环境中正在运行的应用程序的当前状态
    • 监视器模块公开了一组可直接作为HTTP URL访问的REST端点来检查状态
  19. @SpringBootApplication注解是如何工作的?

    • 它是三个注解的组合ComponentScan、EnableAutoConfiguration和Configuration
    • @Configuration:添加该注解的类被视为springboot的配置类,会被初始化创建bean并放入IOC容器中管理
    • @ComponentScan:指定扫描注解的包
    • @EnableAutoConfiguration:给容器导入META-INF/spring.factories 里定义的自动配置类,筛选有效的自动配置类,每一个自动配置类结合对应的 xxxProperties.java 读取配置文件进行自动配置功能
  20. springboot的run启动逻辑,它是如何把项目启动起来的?

    • 调用SpringApplication的run静态方法
    • run静态方法会先调用SpringApplication构造方法new一个SpringApplication实例,然后调用实例的run方法
    • 然后通过debug启动看构造方法中属性值
      • 将当前类作为入参传入构造方法
      • 设置应用类型webApplicationType为SERVLET,即web应用类型
      • 设置初始化器:通过getSpringFactoriesInstances方法获取/META-INF/spring.factories中配置的ApplicationContextInitializer初始化器(实现类)
      • 设置监听器:通过getSpringFactoriesInstances方法获取/META-INF/spring.factories中配置的ApplicationListener监听器(实现类)
      • 最后一步就是推断应用程序的主类,就是我们的入口类
    • 然后分析run实例方法
      • StopWatch计时器:StopWatch实例的start方法用来记录任务执行时间
      • configureHeadlessProperty设置无领导属性:为了能够在不支持显示器、键盘鼠标的环境中也能正常启动
      • 获取SpringApplicationRunListener监听器:通过getSpringFactoriesInstances方法获取/META-INF/spring.factories中配置的SpringApplicationRunListener监听器(实现类):返回子类EventPublishingRunListener,用来在整个启动流程中接收不同执行点事件通知的监听者,SpringApplicationRunListener接口规定了SpringBoot的生命周期,在各个生命周期广播相应的事件
      • 准备环境变量:准备ConfigurableEnvironment环境变量,包括配置属性、系统属性等
      • 打印banner信息:在没有自定义banner图或者文本的情况下,默认调用SpringBootBanner的printBanner方法打印banner信息(将自定义文本banner.txt或图片banner.png放到resources目录下,可以在application.properties配置中指定spring.banner.location或者spring.banner.imgage.location位置)
      • 创建application上下文:createApplicationContext方法创建ConfigurableApplicationContext实例,也是run方法最终返回的对象
      • 准备上下文prepareContext方法:初始化ApplicationContextInitializer;执行Initializer的contextPrepared方法并发布事件;如果延迟加载,添加延迟加载上下文处理器;执行Initializer的contextLoaded方法并发布事件
      • 更新上下文refreshContext方法:真正加载bean到容器中
      • 更新上下文的后置处理:无逻辑
      • StopWatch计时器:StopWatch实例的stop方法,打印初始化时间
      • 发布上下文开始事件:调用SpringApplicationRunListener的started方法发布事件
      • 调用Runner执行器:从ApplicationContext上下文中获取ApplicationRunner和CommandLineRunner执行器,调用其run方法执行
      • 发布上下文执行事件:调用SpringApplicationRunListener的running方法发布事件
    • 总结:Springboot的启动过程大量使用了SPI和事件发布
      • SPI全称Service Provider Interface,一种服务发现机制
      • 通过java.util.ServiceLoader类解析classPath和jar包的META-INF/services/目录 下的以接口全限定名命名的文件,加载该文件中指定的接口实现类,以此完成调用
  21. 如果自己写一个starter,怎么做?

    • 创建一个starter项目,命名可以按照官方推荐的springboot-starter-xxx
    • 创建一个@ConfigurationProperties用于获取application.yml中的配置信息
    • 创建一个AutoConfiguration,引用定义好的配置信息;在AutoConfiguration中实现所有starter应该完成的操作,并且把这个类加入spring.factories配置文件中进行声明:
      • org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.liyuan.hello.configuration.HelloAutoConfiguration
    • install打包项目,之后在一个SpringBoot项目中引入该项目依赖,然后就可以使用该starter了
  22. springboot读取配置几种方式

    • @Value注解:适用于读取单一配置属性
    • @ConfigurationProperties:提供了将多个配置选项注入复杂对象的能力;它要求我们指定配置的共同前缀;一般配合@Component注解交给IOC容器,以便在其他Bean中注入使用
    • @PropertySource:可以加载指定路径的配置文件,默认只支持.properties格式,一般需要配合@Value或者@ConfigurationProperties注解
    • 使用Environment读取配置文件:将该对象注入到Bean中,然后使用getProperty方法读取配置
    • 使用原生的Properties方式读取:使用文件流方式读取配置文件智Properties对象中,然后通过getProperty方法读取配置
  23. 如何将配置读取到static静态变量中

    • 实现InitializingBean接口,在它的afterPropertiesSet方法中将使用@Value读取的变量赋值给static静态变量

    • 或者使用@PostConstruct注解的方法中将使用@Value读取的变量赋值给static静态变量

    • 总结:

      • 先用@Value注解读取到配置文件中的值
      • 然后在spring加载到某一步时,将上面读取的配置值赋值给static静态变量
      • 所以,在使用静态变量时,不能太早,最好等spring加载完成后再使用
      • 如果一定要在spring加载之前获取static变量,那可以在静态方法中直接读取配置文件信息,给static赋值
  24. eureka和zookeeper区别

    • zookeeper保证的是CP,在Zookeeper集群中,当发生网络故障导致master节点和slave节点失联时,剩余的slave节点会进行leader选举,而在选举的过程中,zookeeper集群不可用,不能对外提供注册和查询的服务。
    • eureka保证的是AP,在eureka集群中,某些节点挂掉,只要有一个eureka节点存在,就可以对外提供注册和查询服务,但是可能注册信息不是最新的。
  25. eureka和nacos

    • 共同点:都支持服务注册服务拉取;都支持服务提供者心跳的方式做健康检测

    • 不同点:

      • 临时实例心跳不正常会被剔除,非临时实例则不会被剔除

      • spring.cloud.nacos.discovery.ephemera = false # 设置为非临时实例

      • nacos支持服务列表变更的消息推送模式,服务列表更新及时

      • nacos集群默认采用AP方式,当集群中存在非临时实例时,采用CP模式;eureka采用AP方式

      • nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式(一般情况下都使用临时实例,主动检测消费的服务器资源较大,服务器压力大)

        image

  26. ribbon的负载均衡算法有哪些?

    • 轮训(RoundRobinRule)、随机(RandomRule)、根据响应时间分配权重(WeightedResponseTimeRule)、重试等
    • 原理:@LoadBalanced注解和RestTemplate Bean实现,RestTemplate发送请求,LoadBalancerInterceptor拦截
    • 自定义:实现AbstractLoadBalancerRule抽象类,重写choose方法
  27. ribbon和feign区别

    • Ribbon原理:先去本地获取从Eureka缓存下来的服务列表,然后使用负载均衡算法选取一个服务,使用HttpClient进行调用

    • Feign的原理:

      • 扫描所有加了@FeginClient 的接口,然后针对这个注解的接口生成动态代理
      • 然后你针对feign的动态代理去调用他方法的时候,此时会在底层生成http协议格式的请求,使用HttpURLConnection进行调用
  28. hystrix什么是?

    • Hystix是分布式系统的一个延迟和容错的开源库
    • 可以进行熔断、降级、限流、监控
    • 可以避免分布式系统的级联故障雪崩效应
    • 服务熔断:熔断是直接调用降级方法,不调用目标方法,无需等待接口调用超时才返回结果
    • 服务降级:降级是调用目标方法,由于目标方法调用超时或者异常,才调用降级方法
    • 使用:服务降级是在消费端和feign一起使用,默认降级的配置不是开启的(feign.hystrix.enabled=false)
    • 服务熔断是在服务端使用,对服务端的controller进行熔断,默认熔断的配置是开启的
  29. spring声明式事务原理

    • spring容器在启动时,会为@Transactional标注的类或方法创建一个代理类,在方法被调用的时候,实际调用的是TransactionInterceptor类中的invoke方法,该方法作用就是在目标方法之前开启事务,方法执行过程中如果遇到异常的时候回滚事务,方法调用完成之后提交事务
  30. spring中的事务和传播机制

    • spring中的事务操作分为两种

      • 编程式事务管理:通过API接口实现,使用TransactionTemplate或者TransactionManager手动管理事务
        • 优点:显式的管理事务,灵活性强,易于调试;可以在代码中根据具体业务需要来控制事务的具体范围和属性
        • 缺点:代码复杂度高
      • 声明式事务:通过AOP技术实现,在方法上添加@Transactional注解就可以实现了,进入方法时自动开启事务,方法执行完会自动提交事务【使用PlatformTransactionManager创建事务】
        • 优点:简化代码;可配置性强
        • 缺点:限制较大,事务属性需要在方法或类级别进行声明,会导致某些情况下难以满足特定的业务需求;难以调试,由于事务是在AOP层面进行管理的,在调试时可能难以追踪事务管理的具体细节
    • spring的事务隔离级别使用后端数据库默认的隔离级别

    • spring事务的传播机制

      • 定义:指的是Spring中多个事务在相互调用时, 他们之间的行为方式是如何执行的

      • 七种传播机制:

        • propagation.required:Spring默认的传播机制,能满足绝大部分业务需求,如果外层有事务,则当前事务加入到外层事务,一块提交,一块回滚。如果外层没有事务,新建一个事务执行——特点:一个类调用另外两个类的时候,调用类(一个类)当中有事务,被调用类(其他两个类)如果存在事务,就加入,如果被调用类中出现了错误,就全部回滚,如果没有出现错误,就添加成功。如果不存在事务,就创建一个事务
        • propagation.requires_new:该事务传播机制是每次都会新开启一个事务,同时把外层事务挂起,当当前事务执行完毕,恢复上层事务的执行。如果外层没有事务,执行当前新开启的事务即可
        • propagation.supports:如果外层有事务,则加入外层事务,如果外层没有事务,则直接使用非事务方式执行,完全依赖外层的事务
        • propagation.not_supported:该传播机制不支持事务,如果外层存在事务则挂起,执行完当前代码,则恢复外层事务,无论是否异常都不会回滚当前的代码
        • propagation.never:该传播机制不支持外层事务,即如果外层有事务就抛出异常
        • propagation.mandatory(mandatory:强制性):与NEVER相反,如果外层没有事务,则抛出异常
        • propagation.nested:该传播机制的特点是可以保存状态保存点,当前事务回滚到某一个点,从而避免所有的嵌套事务都回滚,即各自回滚各自的,如果子事务没有把异常吃掉,基本还是会引起全部回滚的
      • 嵌套事务nested和加入事务required的区别

        • 整个事务如果全部执行成功,二者结果是一样的
        • 如果事务执行到一半失败了,加入事务:整个事务会全部回滚;而嵌套事务会局部回滚,不会影响到上一个方法中执行的结果
    • spring中事务不生效的可能原因

      • 手动抛出Exception异常,而Exception是RuntimeException的父类:Spring事务默认支持RuntimeException异常,抛出的异常为RuntimeException异常及其子类异常事务均可生效
      • 使用了try/catch:异常被try catch块捕获,导致事务失效
      • 事务方法为private/final/static方法:Spring声明式事务基于动态代理实现,private/final/static方法不能被代理,事务不会生效
      • 类未被spring管理:Spring实现对象的动态代理,首先这个对象要交由Spring管理
      • 一个方法调用本类中另一个方法,事务失效:@Transactional基于AOP实现,而AOP又是基于动态代理实现,直接调用本类方法或使用this调用本类方法,均不是Spring的代理对象,无法实现动态代理,事务也就不会生效
      • 数据表不支持事务:Spring事务基于数据库事务实现,有些数据表本身不支持事务,如MySql的MyISAM引擎,事务自然不生效
    • 多线程中如何实现spring事务

      • spring的声明式事务在使用多线程时,并不会生效
      • 可以使用spring提供的编程式事务解决;核心思路是为每一个线程都开辟一个事务
  31. gateway的过滤器和zuul的过滤器底层有啥不一样

    • gateway
    • zuul
  32. hystrix两种隔离模式

    • 信号量
    • 线程池(默认)
  33. Spring Cloud中如何保证各个微服务之间调用的安全性?

    • spring security安全认证机制
    • 请求体Body中加入参数校验 => SDK集成场景较多(微信一些接口,会有签名)
    • API网关转换外部请求时打上标签tag
    • 请求头Header中加入认证信息 动态token(一定程度上能够防止刷接口)
      • 公共的认证服务使用JWT安全标准,来制定我们的认证机制
      • 在网关出通过滤器来统一添加token至请求头中,该token可以通过定时任务调用认证服务生成,有效期15min,每隔15分钟重新生成Token
      • 各个下游业务微服务通过拦截器,调用认证服务,校验token有效性
  34. Spring Cloud中Hystrix 线程隔离导致ThreadLocal数据丢失

    • 需求:传统微服务中,内部通讯默认为安全,不需要鉴权,但我们项目要求内部接口不能被外部访问,需要做鉴权;所有请求通过gate-way网关进入,转换为内部请求时,在网关全局过滤器GlobalFilter中动态生成校验microToken,添加到request-header中;下游微服务通过HandlerInterceptor进行拦截,并获取microToken,校验通过之后,放到ThreadLocal中;内部微服务调用时,采用feignclient拦截器RequestInterceptor获取到ThreadLocal中的microToken,再次添加到request-header中,调用其他微服务。

    • 问题复现:发现在RequestInterceptor拦截器中获取不到之前放入ThreadLocal中的microToken数据

    • 原因排查:通过日志发现两边的线程发生了变化,并不是同一个线程了,致使取不到值,致使线程发生变化的原因就是显示开启了feign.hystrix.enabled,Hystrix 线程隔离导致ThreadLocal数据丢失

    • 处理方法:如何让ThreadLocal变量信息在HystrixCommand执行时能在Hystrix线程中正确的传递?

      • 方法一:就是将hystrix的隔离模式改为信号量模式,就不存在线程池复用导致线程发生变化的问题,但是信号量只能实现限流,没法实现超时熔断

        • 实现:

          hystrix.command.default.execution.isolation.strategy = SEMAPHORE

          hystrix.command.default.execution.isolation.semaphore.maxConcurrentRequests = 100

      • 方法二(无效):InheritableThreadLocal:可以将当前线程中的线程变量信息共享到当前线程所创建的「子线程」中

        • 但是Hystrix中的线程模式底层使用的是自己维护的一个线程池,会出现复用的情况,那么就会出现每个线程所共享的信息都是之前首次获取到的「父线程」的共享信息,如果线程池中线程长期存活,那么我们就没法获取到定时更新的microToken
      • 方法三:使用hystrix插件,HystrixConcurrencyStrategy(hystrix并发策略,包含真正创建线程池的逻辑):

        • 实现:

          自定义hystrix策略继承HystrixConcurrencyStrategy,重写wrapCallable方法,手动在新线程中设置ThreadLocal

          重置Hystrix插件,并将自定义并发策略注册到插件上

  35. JWT

    • 全称JSON WebToken,一个轻量级身份认证规范,方便用户和服务器之间传递安全可靠的信息

    • 原理:解决传统的跨域认证问题,传统方式是共享session,JWT服务端无状态,不保存用户信息,而是生成token下发给客户端进行保存,为了防止用户篡改数据,服务器在生成这个对象的时候,会加上签名

    • JWT组成:头部header、透传数据payload、签名signature,三个部分之间.连接

      • header:描述JWT最基本信息,包括typ(声明类型,JWT)和alg(声明签名使用的算法,HMAC-SHA256)两部分信息
      • payload:存放有效信息,包括标准中标注的(issuer/issuerAt/expiration)、公共声明和私有声明(自定义claim)
      • signature:由Base64后的header、Base64 后的payload以及秘钥
    • 注意

      • 一般JWT生成签名采用HS256的AES对称加密算法,秘钥secret是保存在服务端的,用于签名的加密和解密
      • JWT本身默认不加密的,只是采用base64算法,拿到JWT字符串后可以转换回原本的JSON数据,上述的加密仅仅是指签名,可以对生成的Token在进行一次加密
      • 生成的token保存在客户端,每次请求服务端会携带token,在服务端进行校验
      • 由于服务端不保存session状态,因此无法在使用过程中废止某个 token,一旦token签发了,在到期之前就会始终有效,除非服务器部署额外的逻辑
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值