Spring的核心功能IOC(控制反转,依赖注入),AOP(面向切面的编程)
IOC:我们在使用过程中不用关注于对象是怎么创建的,只用应用过去,sping自动帮我们完成注入,对象的创建,spring默认创建对象是单例,这样减少了频繁创建对象,让对象重复利用,所有的对象都是放在BeanFactory 工厂的
AOP:面向切面的编程,我们可以把一些公共的东西模块化,做成一个切面,在方法的运行过程中织入进去,好处是解耦,提高代码的重复利用率
我们经常使用的事务@Transactional的底层就是aop去实现的,还有日志,权限认证
Aop底层其实就是通过动态代理去实现的,分为jdk的动态代理和cglib,jdk的动态动态代理必须要实现接口,cglib是以继承的方式子类重写父类的方法增强,spring默认会优先采用jdk的动态代理,如果没用实现接口再采用cglib代理
singleton(单例)
Prototype(原形范围与单例范围相反,为每一个bean请求提供一个实例)
Request(在请求bean范围内会每一个来自客户端的网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收)
Session(与请求范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效)
global-session
@RestController和@Controller有什么区别?
@RestController是@Controller和@ResponseBody的组合,返回的是json
@Controller默认跳转的是页面,返回json需要方法加上@ResponseBody
谈到beans线程安全那么就看bean是否有多种状态,如果始终只有一种状态 就是线程安全的,否则需要自己去保证线程的安全,可以采用将singleton变为prototype
(1)客户端(浏览器)发送请求,直接请求到DispatcherServlet。
(2)DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler。
(3)解析到对应的Handler后,开始由HandlerAdapter适配器处理。
(4)HandlerAdapter会根据Handler来调用真正的处理器开处理请求,并处理相应的业务逻辑。
(5)处理器处理完业务后,会返回一个ModelAndView对象,Model是返回的数据对象,View是个逻辑上的View。
(6)ViewResolver会根据逻辑View查找实际的View。
(7)DispaterServlet把返回的Model传给View。
(8)通过View返回给请求者(浏览器)
Spring 支持 7 种事务传播行为:
PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与
PROPAGATION_REQUIRED 类似的操作。
Spring是如何解决循环依赖问题的?
循环依赖就是:A依赖B ,B依赖A ,采用三级缓存
先对A进行实例化,首先创建一个A的对象,将这个对应的lambda表达式存入 三级缓冲中去,由于A依赖于B所以要填充b的属性,那么这个时候会去一级缓存中去寻找B的对象,没有找到,那么就进行创建(和A创建一模一样),先去创建B对象放入三级缓存中去然后填充A的对象属性,这时候要先去一级缓存中去寻找A如果没有找到在去2级缓冲中去找,如果二级还没有再去三级缓冲中去找(因为此时a的对象存放在了3级缓冲中,所以说在三级缓冲中查询到了,因为三级缓冲是一个lambda表达式,所以执行这个表达式,然后将返回的对象放入 二级缓冲中去,进行A的填充),A进行填充之后,去执行B的对应的表达式返回对象,并将B的对象放入一级缓存,因为此时B已经完全创建好,但是A还没有创建完成,此时吧B从一级缓冲中取出来,填充到A中去,此时就A业创建好了,就把二级缓冲中的A放入一级缓冲就完成了
Spring Boot 底层实际上主要的有三个注解:Configuration ,EnableAutoConfiguation
ComponentScan,它会读取META-INF下的spring.factories文件信息,通过反射的机制把bean纳入到spring的管理
byName:根据名称进行自动匹配
byType:根据类型进行自动匹配
constructor:构造函数注入
autodetect:根据Bean的自省机制决定采用byType还是constructor进行自动装配,如果Bean提供了默认的构造函数,则采用byType,否则采用constructor
Autowired是通过bean类型注入的,如果一个接口有多个实现,那么采用Qualifier配合使用
,Resource是通过bean名称注入的
BeanFactory:它是一个bean工厂,spring把对象创建好后都会放入这个工厂,底层存储对象其实就是一个大的ConcurrentHashMap存储的对象实例
FactoryBean:它是一个特殊的bean,实现了这个接口,可以通过getObject获取到自定义的bean
通过refresh方法里面完成bean的创建,先会去创建BeanFactory,然后扫描包转换成beanDefinition,通过后置处理器完成,实例化,属性赋值,初始化,销毁,每个阶段可以实现不同的接口,如:初始化的时候实现InitalizingBean接口,调用afterPropertiesSet() 方法,销毁的时候实现DisposableBean接口,调用destory() 方法
Eureka 注册中心
ribbon:负载均衡策略
hystrix:熔断器
zuul:网关
config:配置中心
feign:服务调用
springboot主要快速开发整合包,他主要是方便单个的微服务,而springcloud是治理框架,将每个单个的微服务结合起来,并且为他们提供配置,服务发现,路由等集成服务
随机,轮询,最小使用数,权重
统一的请求路由,权限认证,安全校验,限流
一个服务在调用另一个服务的时候由于网络的原因出现了问题,调用者会一直等待被调用的者的响应,当更多的请求要调用会出现更多的请求等待,所以断路器完全打开状态:一段时间内,没有得到被调用者的响应,多次检测没有恢复的迹象,这个时候断路器完全打开;断路器半开状态:有恢复的迹象,将部分的请求发给服务;如果正常调用没有出现等待请求那么处于断路器关闭。
分布式系统中,服务数量比较多,要想实现一个统一管理,实时更新,需要一个配置中心组件,在springcloud中用的是springcloudconfig去实现的,他是可以放在内存中也可以放在git仓库中的,主要有两个角色一个是connfig server和config client 使用就是1、加pom依赖 2、相关的配置文件,3、启动类加enableconfigserver
springcloud的gateway是网关,取代了zuul官网,在微服务中有重要的作用,常见的功能有路由,权限验证,限流控制具体是route去处理的,filters是各种过滤器。
熔断器是起来保护的作用,和保险丝一样,到了某个领结点就会进行熔断保险丝保护电路,springcloud中的熔断机制也是如此,如果某一服务发生了崩溃那么要进行熔断机制防止整个系统都崩溃
- eureka是基于AP设计的,zookeeper是基于CP设计的
c:一致性 a:可用性 p:分区容错性
- ZooKeeper有Leader和Follower角色,Eureka各个**节点平等 **
- eureka可以很好的解决出现故障导致的部分结点失去联系,zookeeper如果出现故障整个服务器都会瘫痪
- ZooKeeper只是一个进程,Eureka本质上是一个工程
- zookeeper采用半数存活原则,eureka采用自我保护机制解决分区问题
eureka保证了可用性,eureka各个节点都是平等的,几个结点挂掉是不会影响正常工作的,如果eureka的客户端注册失败的话,会自动切换其他节点,只要还有一台eureka还在的话就能保证可用性,eureka还有 自我保护机制,如果超过了15分钟有85%的结点都没有心跳了,那么就认为客户端出现了网络故障
zookeeper保证了一致性,但是我们在注册信息的时候是没有办法容忍服务器宕机的。也就是说服务的可用性要高于一致性。zookeeper会出现一种情况当主节点因为网络原因与其他的结点失去联系的时候,剩余的结点会进行一个leader选举,但是选举的过程中是时间很长的达到30—120秒,在选举的过程中zookeeper是没有办法使用的,在云部署的情况下zookeeper主结点丢失这种情况的概率是很大的,虽然可以恢复但是时间长。
eureka主要是通过心跳检测去判断的,有一个发送者和客户端,发送者会每隔30秒发送一个心跳到eureka上去,服务端会把eureka上的客户端发送的数据进行一个接受并调用的过程,如果说生产者没有发送心跳到注册中心上,那么就直接剔除掉,将所有的接口都剔除掉,如果说中途eureka发生了宕机,那么也是可以进行一个调用的,因为将原来的数据放到了一个缓存中 去,并且eureka还有自我保护机制,如果说在15分钟内检测到有85%的服务都宕机了那么这个时候就会认为是一个网络的问题导致的
底层基于动态代理发送http请求,然后通过负载均衡算法调到对应的服务机器上
- 隔离(线程隔离和信号量隔离)
- 熔断
- 降级
- 缓存 将请求放到缓存中
隔离:线程隔离:主要是交给线程去做处理的,每个请求都要交给线程去做处理,是可以处理突发情况的(因为如果没有及时处理的数据是要放到队列中去,一点一点执行的),是异步的
信号量隔离:主要是采用原子计时器(信号量)去对请求做处理的,如果说发送一个请求,当前线程数已经大于最大线程数,那么就会采用一个拒绝,不接受请求,如果没有就计数器+1,当返回结果后在进行计数器-1,这个是立即返回给用户的,灭有办法处理突发情况,是同步的
熔断:如果说长时间没有返回给客户请求响应,那么会进行熔断开启状态,这个时候会拒绝所有的请求,过段时间会进入熔断半开状态 要接收一部分请求做出响应。
降级:忍痛割爱 要把一些服务器先停掉,等到执行完之后再将其打开