Spring的loc
Ioc: 叫做控制反转
以前都是我们自己创建对象,耦合性高,不利于后期维护,现在我们把创建对象的权力反转交给Spring帮我们创建对象,因为Spring底层采用的是工厂设计模式+xml+反射,所以创建的对象是低耦合的。
Di: 依赖注入
当我们把多个对象都交个了Spring后,我们只需要通过配置文件告诉Spring这些对象有什么依赖关系,Spring在管理对象时会帮我们把这些对象的依赖关系处理好,当我们用到这些对象时,我们拿到的实际上就是一个完整的对象。
依赖注入有很多种实现方式:完成依赖注入的方式
1、比如set方式 setter方式注入
分类两类
a、bean类型
b、非bean类型
需要在配置文件中,去书写property
name :要去调用哪个set方法
ref : 要把谁传递到这个set方法中去
value:要把谁传递到这个set方法中去
针对一些配置属性,我们最好还是按照setter来玩,因为如果你把参数写在代码中,如果你想要切换一些属性,你就得修改代码
2、自动装配注入
3、集合注入
4、构造器注入
Bean的实例化方式:指的创建对象的方式
1、构造方法
2、实例工厂
3、静态工厂
厂中厂
Spring的AOP原理
aop是一种横向切面编程思想,他和面向对象编程oop的区别是:
oop是由上往下或者由下往上看问题,有共性的内容就向上抽取一个父类,然后让子类去继承父类,但是这种做法会出现两个问题,第一,体系问题,oop是单继承体系而且不是所有类别都能继承,比如用map去继承list,明显不合理。而且继承完后子类还需要手动调一下父类的方法,不够灵活。
而aop是横着看问题,他把所有共性的内容都进行抽取,直接把这些共性的内容制作成一个独立的模块,就是我们说的通知,然后通过和切入点绑定形成切面,将通知类中具体的方法放入到具体的目标方法的具体位置上,完成整个aop的逻辑。
aop的底层是基于代理模式,代理模式有动态代理和cglib代理,而动态代理又是基于静态代理,静态代理的底层是基于装饰者设计模式,所以他可以在不惊动原始目标类的基础上进行功能增强。
动态代理
代理实际上就是找个人帮你完成一些事情。
代理分成很多种
1. 静态代理
静态代理是基于装饰者设计模式的,你每一次增强,就需要多写一些代码。
2. 动态代理
其实动态代理得底层就是静态代理
JDK的动态代理,就是在程序运行的过程中,根据被代理的接口来动态生成代理类的class文件,并加载运行的过程,只支持接口代理
3. cglib代理
spring中bean的作用域
Spring支持如下5种作用域:
(1)singleton:默认作用域,单例bean,每个容器中只有一个bean的实例。
(2)prototype:为每一个bean请求创建一个实例。
(3)request:为每一个request请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
(4)session:与request范围类似,同一个session会话共享一个实例,不同会话使用不同的实例。
(5)global-session:全局作用域,所有会话共享一个实例。如果想要声明让所有会话共享的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。
Spring的Bean是否线程安全
- 单例:创建的对象是同一个对象
- 多例:创建的对象不是同一个对象
Spring中的bean线程安全吗?
当他是单例的时候,对于方法中的局部变量没有影响,但如果在对象中创建了一个成员变量,就会出现线程安全问题,除非能保证这个成员变量不会被修改或者在操作这个成员变量时给他上了锁。
而多例就无所谓
Autowired自动装配
- 先按照类型注入
- 然后会自动按照名称注入,但实现类的名称和当前的接口名称要保持一致。
Spring的事务管理
- 事务从本质上来说一定是数据库提供的,spring管理数据库也是基于数据库事务的基础上。
- 编程式事务:在原有业务代码的基础上书写代码管理事务,但是这样的代码侵入性过高,而且学习的成本过高。
- 声明式事务:是指利用aop来实现事务,他的底层还是基于编程式事务那套代码,只不过是把这些代码封装成了切面,在不惊动原始代码的情况下,通过aop把这些事务管理的代码在运行的时候重新织入回原来的代码,实现spring管理事务。
Spring的事务传播行为
- 我们每一次在操作数据时,无论操作成功没有,都需要记录下来这次操作
- 如果你的原始操作和记录日志这个操作在同一个事务,当事务失败时就无法完成记录的操作
- 但事务方法和事务方法之间应不应该在同一个事务中不好说,得根据业务需求来定
- spring提供的这么一种机制,就是让我们在不同业务中去控制对应的事务,七种
- requeied
- 如果没有事务,则创建事务,有事务,就加入事务
- requeied_new
- 无论有没有事务,都会新建一个事务
Spring的事务失效有哪些情况
- 当前这个类不归spring管
- 业务层try,catch把异常吃掉了
- 没有配置有关事务的操作,spring无法提供对对应事务的支持
- spring的异常机制只会处理运行时异常,如果抛出的是编译期异常,spring的事务也会失效。
- 数据库本身就没有事务
- 默认情况下,只支持public的事务处理
Spring的生命周期?(高薪常问)
- 实例化一个Bean,也就是我们通常说的new
- 按照Spring上下文对实例化的Bean进行配置,也就是IOC注入
- 如果这个Bean实BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的是Spring配置文件中Bean的ID
- 如果这个Bean实现了BeanFactoryAware接口,会调用它实现的setBeanFactory(),传递的是Spring工厂本身(可以用这个方法获取到其他Bean)
- 如果这个Bean实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文,该方式同样可以实现步骤4,但比4更好,因为ApplicationContext是BeanFactory的子接口,有更多的实现方法
- 如果这个Bean关联了BeanPostProcessor接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor经常被用作是Bean内容的更改,并且由于这个是在Bean初始化结束时调用After方法,也可用于内存或缓存技术
- 如果这个Bean在Spring配置文件中配置了init-method属性会自动调用其配置的初始化方法
- 如果这个Bean关联了BeanPostProcessor接口,将会调用postAfterInitialization(Object obj, String s)方法
注意:以上工作完成以后就可以用这个Bean了,那这个Bean是一个single的,所以一般情况下我们调用同一个ID的Bean会是在内容地址相同的实例 - 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean接口,会调用其实现的destroy方法
最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法
Spring框架中都用到了哪些设计模式?(必会)
工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例
- 单例模式:Bean默认为单例模式
- 代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术
- 模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate
- 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知被自动更新,如Spring中listener的实现—ApplicationListener
SpringBoot
起步依赖
springboot工程在创建的时候,springboot都会搞一个parent父类依赖,这个父类依赖只定义很多个版本,把这些版本统一进行管理,而子类在书写依赖的时候,就可以不用再去书写版本。
自动装配
- 自动装配:不用书写配置文件,springboot默认帮我们把配置文件处理好
- 原理:
- 首先用SpringBootApplication注解标明配置类,这个注解中有一个包扫描的注解,可以让当前这个配置类扫描这个类所在的包及其子包。
- 而SpringBootApplication这个注解中还存在一个EnableAutoConfiguration注解,这个注解中的import注解就会去引入ImportSelector这个接口的实现类AutoConfigurationImportSelector,调用实现类中的selectImports这个方法,返回一个String【】数组,这个数组中包含了很多个和配置有关的类,springboot会自动的帮我们用反射把数组中的对象创建出来。
- 当springboot拿到这些类后,就会根据这些类上的ConditionalOnClass注解判断是否配置了当前类的起步依赖,就是判断是否导入了当前类的jar包。
- 当我们配置了当前类的起步依赖,就会调用当前类的方法,通过方法上的ConditionalOnMissingBean注解判断我们是否自己书写了配置文件,如果写了,springboot就默认按照我们自己写的走,没写,springboot底层就会自动帮我们创建出来一个配置文件配置这个对象的属性。
nginx正向代理和反向代理
- 正向代理:
- 用户自己寻找代理服务器对其他服务器进行访问
- 反向代理:
- 服务器端配置代理服务器, 客户端不需要任何配置就可以访问,只需要将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器获取数据后,暴露的是代理服务器地址,隐藏了真实服务器 IP 地址
- 负载均衡
- 轮询
- upstream模块默认的负载均衡默认策略,一人一次
- weight 权重随机
- 按权重的方式随机分配
- ip_hash
- 基于客户端ip分分配,确保了相同的客户端的请求一直发送到相同的服务器
- least_conn
- 此负载均衡策略适合请求处理时间长短不一造成服务器过载的情况
- fair(第三方)
- 按照服务器端的响应时间来分配请求,响应时间短的优先分配
- url_hash(第三方)
- 可以使得同一个url(也就是同一个资源请求)会到达同一台服务器,一旦缓存住了资源,再此收到请求,就可以从缓存中读取。
- 一致性哈希
- 普通哈希策略在某个服务器出现宕机的情况下,数据迁移时可能会影响很多服务器,而一致性哈希则不会,他是一个0-2的32次方-1的圆形闭环,服务器根据ip或者主机名求hash值然后对应到hash环上,客户请求时会根据它的ip进⾏hash求值,对应到环上某个位置,然后顺时针找到最近的服务器,如果某个服务器宕机后,它只需要将数据迁移到下一个服务器即可,不会影响其他服务器。但是可能会存在服务器节点太少,节点分布不均出现数据倾斜问题,为了解决这种数据倾斜问题,⼀致性哈希算法引⼊了虚拟节点机制,即对每⼀个服务节点计算多个哈希,每个计算结果位置都放置⼀个此服务节点,称为虚拟节点,当用户访问到虚拟节点时会带到对应的真实节点。
- 轮询