Spring视频零基础入门到高级,spring全套视频教程详解_哔哩哔哩_bilibili动力节点
课程笔记:Spring6 密码mg9b
动力节点老杜,详细讲解。(这部分涉及spring基础、手写spring框架,基础忘了可以看)
2021最新版 SpringBoot 源码剖析全集(27P),P8阿里大神都收藏的全网最详细教程,从0到1手把手教你写源码_哔哩哔哩_bilibili上面是拉钩教育是springboot。
孙哥说Spring5:从设计模式到基本应用到应用级底层分析,一次深入浅出的Spring全探索。学不会Spring?只因你未遇见孙哥_哔哩哔哩_bilibili
什么是Spring? 死背咯
- Spring是一种轻量级Java框架
- 一般指的是SpringFramework,它是很多模块的集合,模块方便协助我们开发。比如Spring支持IOC和AOP,有web、aop、核心容器、工具、消息、测试模块。
Spring的一些模块?死背咯
- Spring Core:这是Spring框架最基础的部分, 它提供了依赖注入(DependencyInjection)特征来实现容器对Bean的管理。核心容器的主要组件是 BeanFactory,BeanFactory是工厂模式的一个实现,是任何Spring应用的核心。它使用IoC将应用配置和依赖从实际的应用代码中分离出来。
- Spring Aspects:该模块为与AspectJ的集成提供支持。
- Spring AOP:提供面向切面的编程实现。
- Spring Bean:Bean的创建、配置和管理。
- Spring JDBC:Java数据库连接。
- Spring tx: 事务的支持
- Spring Web:为创建Web应用程序提供支持。
- Spring Test:提供了对JUnit和TestNG测试的支持。
- Spring JMS:Java消息服务。
结合图记一下
Spring中用到了哪些设计模式【重点】?
单例,代理,模板方法,工厂,观察者
014-对Spring的第一个程序小细节2_哔哩哔哩_bilibili(BeanFactory)
单例:bean的作用域用到了单例bean,spring本身就是一个单例bean的管理。
代理:AOP的时候用到了动态代理,有两种实现方式,jdk和cglib。
模板方法:定义父抽象类或者接口,父类定义模板方法,部分抽象方法延迟到子类中定义。像JdbcTemplate和RedisTemplate还要hibernateTemplate就是典型的模板方法模式。
工厂模式:Spring中顶级接口BeanFactory就是工厂模式的实现。包括其扩展接口ApplicationContext容器类似于工厂模式的一种实现。 (所以说SpringIOC底层是基于 工厂模式+xml解析+反射实现的)
观察者模式:在我的项目中用到了Spring事件驱动模型,通过实现ApplicationContextAware接口获取ApplicationContext上下文,调用上下文的publishEven方法。监听者通过@EventListener注解进行监听。
IOC
开闭原则?
004-软件开发原则之OCP开闭原则_哔哩哔哩_bilibili
对扩展开放。对修改关闭。
只要你在扩展系统功能的时候,没有修改以前写好的代码,那么你就是符合0CP原则的。
反之,如果在扩展系统功能的时候,你修改了之前的代码,那么这个设计是失败的,违背0CP原则。
依赖倒置原则?
006-控制反转IoC思想的理解_哔哩哔哩_bilibili
上层强依赖下层。
原则:面向接口编程,不要面向具体实现编程。
目的:降低耦合度,提高扩展力。
说一说IOC和AOP?背前几句话
Ioc控制反转
-
IOC也叫控制反转,其实是一种设计思想。就是说将本在程序中 手动创建对象的控制权,交给spring管理。Ioc这个思想在其他语言中也有。
-
控制 是指对象的创建和管理的权利
-
反转 控制权交给Spring等Ioc容器 (new 对象不需要程序员new了,对象直接的关系也不用管了,给IOC容器管)
-
对象之间的依赖关系给Ioc容器管理,简化开发。我们需要一个对象的时候,只需要用配置文件/注解获取,不用关系对象的创建。(换句话说将创建对象过程和具体业务解耦,有点像工厂)
-
例如在项目中,controller中需要用Service类,service可能又依赖了其他的类,之前的方式是实例化这个service时还需要搞清楚他的构造函数去手动构造它,利用Ioc时只需要配置好,在需要的地方引用注入就行了。
DI 依赖注入是什么
- 控制反转是思想。依赖注入是这种思想的具体实现。
- 依赖注入DI(就是给属性赋值),又包括常见的两种方式:
-
- 第一种:set注入
- 第二种:构造方法注入
- autowired注解注入
DI依赖注入是如何实现的呢?(阿里)
依赖注入嘛,也就是属性赋值,是Bean的生命周期的一部分,在Bean实例化完成之后进行依赖注入
-
set方法注入
-
构造器注入
-
autowired和resource注解的注入
那IOC和工厂模式有什么区别(进阶)
Spring IOC与工厂模式_spring ioc用的是哪种工厂模式-CSDN博客
记住BeanFactory和applicationContext这两个接口。
这篇文章讲了springIOC和工厂模式的区别,以及springIOC容器创建对象过程的原理 (读文件全类名-->构造BeanDefinetion-->根据BeanDefinetion创建Bean对象 并放入缓冲池中 ) 。
我的理解:springIOC和工厂模式,类似于一种实现方式
- 工厂模式使用new创建对象,而springIOC使用反射创建的(通过反射读取xml文件构造beanDefinition,根据beanDefinition创建Bean)。
- 所以springIOC更灵活,可以在运行时添加新的对象。而工厂模式中有新的对象需要放入工厂需要改代码。
依赖注入,注入的时候有几种方法?
-
基于构造函数的注入。
-
基于setter方法的注入。
-
基于 @Autowired注解注入。
Bean如何实现懒加载?效果是什么?(华为)
@Lazy注解
- 懒加载在 依赖注入的时候,不会真的去单例池(一级缓存)中找对象,而是创建一个新的对象? 。
后面要用的时候再去Spring容器一级缓存中寻找这个Bean,可以解决一个循环依赖的问题。
AOP
AOP面向切面编程
- AOP面向切面编程,核心思想是 将与 核心业务无关,但被业务模块 共同调用的 横切关注点(例如日志、事务、权限控制、接口限流) 从核心业务中 分离出来实现解耦。通过动态代理 或 字节码操作 实现代码解耦合。
- 横切关注点 一般是 分散在多个对象和类 中的公共行为(例如日志、事务、权限控制、接口限流) ,如果每个类或方法都重复,会导致代码冗余。(达到减少重复代码,解耦合,可拓展的目的)
- 例如日志,对于一些方法记录日志,没有AOP时需要重复挨个写。有AOP后,将日志逻辑封装成切面,然后指定哪些方法需要日志记录。
AOP的实现方式?
有 动态代理 和 字节码操作 两种方式:
动态代理: (SpringAOP采用的是动态代理,且是运行时增强)
- JDK动态代理:要求被代理的类实现了某个接口,生成的代理类同样是这个接口的实现,但不是目标类(与目标类是兄弟关系)
- Cglib动态代理:目标类如果没有接口,生成一个 目标类 的子类 作为代理类。(是目标类的儿子)
字节码操作(静态代理): AspectJ基于字节码操作的方式,是编译时增强
拓展: 为什么JDK动态代理要求 被代理类 实现接口,只能代理接口
因为JDK动态 代理自动生成的代理类 $Proxy0继承了java.lang.reflect.Proxy类,由于java是单继承的,所以这里没有机会再去继承被代理类。
动态代理和静态代理?(重点)
具体看动力节点老杜
094-GoF代理模式之静态代理代码实现_哔哩哔哩_bilibili
- 静态代理:自己写一个公共接口,然后写一个目标类和代理类都实现 接口并重写方法,将目标类对象作为代理类的成员, 并在代理类中调用目标类的方法。通过代理类的方法去操作目标类并进行相应的增强。
- 动态代理:运行时创建代理类,如基于jdk的动态代理。
静态代理和动态代理有什么区别?
- 一个编译时确定,一个是运行时才确定。
- 静态代理为目标类手动写代理类,动态代理通过反射生成代理类,更加灵活。
动态代理是什么?(记一记重点)
- 在运行时生成一个目标类的代理类。目标类和代理类实现相同的接口或者是继承关系。
- 在代理类方法中对目标类进行增强,并调用目标类的一些方法。
有 jdk和CGlib两种方式.........,满足开闭原则。
jdk动态代理如何实现
Proxy.newInstance(classLoader, interface数组,目标类)
@Autowired 和 @Resource 的区别是什么?
-
@Autowired 是 Spring 提供的注解,@Resource 是 JDK 提供的注解。
-
@Autowired 默认的注入方式为byType(根据类型进行匹配),如果有多个实现类注入方式会变为
byName。 @Resource默认注入方式为 byName(根据名称进行匹配),如果通过name找不到会变成byType。 -
当一个接口存在多个实现类的情况下,@Autowired 和@Resource都需要通过名称才能正确匹配到对应的 Bean。Autowired 可以通过 @Qualifier 注解来显式指定名称,@Resource可以通过 name 属性来显式指定名称。
-
@Autowired 支持在构造函数、方法、字段和参数上使用。@Resource 主要用于字段和方法上的注入,不支持在构造函数或参数上使用。
Spring中bean的作用域有哪些?死背咯?
- singleton: 单例的。
- prototype: 每次请求都会创建一个新的bean实例。
- request(仅 Web 应用可用) : 每次HTTP请求都会产生一个新的bean(请求bean),仅在当前HTTPrequest内有效。
- session(仅 Web 应用可用) : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean(会话 bean),该 bean 仅在当前 HTTP session 内有效。什么是HTTPsession:Session_http session 什么意思-CSDN博客
- application/global-session(仅 Web 应用可用) :每个 Web 应用在启动时创建一个 Bean(应用 Bean),该 bean 仅在当前应用启动时间内有效。
- websocket(仅 Web 应用可用):每一次 WebSocket 会话产生一个新的 bean。
定义方式,通过scope注解定义
@Bean
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Person personPrototype() {
return new Person();
}
Spring Bean 的生命周期说一下
小白也能懂的最详细之spring-bean生命周期讲解_哔哩哔哩_bilibili
如何叙述Spring Bean 的生命周期,让面试官眼前一亮!_哔哩哔哩_bilibili
- 创建实例化bean,通过反射进行实例化。(读取xml配置文件构造beanDefinition集合,根据beanDefinition进行反射实例化)
- Bean的属性赋值/填充 和 依赖注入。(例如@Autowired 等注解注入的对象、@Value 注入的值、setter方法或构造函数注入依赖和值、@Resource注入的各种资源)
- 调用bean的初始化方法,某些bean可能通过
init-method xml配置或@postConstruct注解设置了初始化方法。 - 使用Bean。
- 销毁Bean,调用bean销毁前的方法。调用配置文件中的定义包含
destroy-method属性 或者 通过@PreDestroy注解标记 Bean 销毁之前执行的方法。
bean生命周期七步的版本
或者看老杜
小白也能懂的最详细之spring-bean生命周期讲解_哔哩哔哩_bilibili
在Bean初始化前后有 beanPostProcessor接口 的方法
实现 beanPostProcessor 接口 并实现两个方法(这个接口是另外需要注入的bean,并在方法中判断bean的名称)。
bean生命周期十个步骤版本
在beanPostProcessor的before方法前后,又有两个方法
- 实现BeanNameAware接口的setBeanName方法
- 实现 InitializingBean接口的afterPropertiesSet方法
- 实现 DisposableBean接口 的 destroy 方法,(配置的destroy-method之前调用)
spring aop对象的创建
在执行IOC流程的时候,(在bean进行初始化之后)顺带就会创建代理对象,但不是所有bean都需要代理对象。
Bean初始化(不是实例化)之后执行代理对象流程,判断是否需要创建代理,获取所有advisor与目标bean进行匹配,然后将目标对象绑定advisor,
然后传递给 由proxyFactory去创建代理对象。
Spring如何解决循环依赖问题?难
Spring 如何解决循环依赖 - LARRY1024 - 博客园
极客时间课程
058-Bean的循环依赖之源码分析_哔哩哔哩_bilibili(老杜,讲得比较浅)
如何解决Spring循环依赖?P8大佬带你源码深度剖析!【2022最新版】_哔哩哔哩_bilibili(详细版本)
华为二面:Spring是如何解决循环依赖的?为什么一定要三级缓存?二级缓存能不能解决循环依赖?_哔哩哔哩_bilibili
循环依赖产生的地方:
A依赖B,B依赖A。
在A实例化完之后进行依赖注入属性赋值,因为依赖B所以需要getBean(B)去map中找。B不存在这时也需要进行创建,B也是实例化然后属性注入,B属性注入A,再去getBean(A) ,A这时因为还没创建完成也不存在,就死循环了。
在没有AOP的情况下用两级缓存可以解决
例如,在A进行实例化之后先放入 二级对内的缓存(外部不能获取),那么在B注入getBean(A)时可以从二级缓存中获取到A的引用,然后A完成注入和初始化后 把A从二级缓存放入一级缓存。
二级缓存存在的问题
但这样在aop的情况下有问题,因为A初始化后会产生A的代理对象(并且后续使用也是用代理对象),而B中从二级缓存获取的A是原目标对象。 (目标对象在后续是被抛弃的对象了)
如何解决?
058-Bean的循环依赖之源码分析_哔哩哔哩_bilibili(老杜,讲得比较浅)
三级缓存,三个map
一级缓存:Map<String, Object> singletonObjects
- 对外提供单例bean,也就是创建完成的完整的bean。
二级缓存:Map<String, Object> earlySingletonObjects
- 存放正在创建的bean,对内,三级缓存获取的代理对象会放入二级缓存中。
三级缓存:Map<String, ObjectFactory> singletonFactories:
- 存beanid与bean的对象工厂
ObjectFactory映射,该工厂会通过目标bean创建代理对象ObjectFactory.getObject(),方法只会被调用一次(因为只会创建一个代理),创建的代理对象会放入二级缓存。
步骤,
- 创建bean A时,将刚实例化(未创建完成)的bean的工厂立即放入三级缓存beanFactory(beanA专属的Factory)。
- 后续在内部获取注入bean A时,在一级缓存找不到,二级缓存找不到,获取三级缓存的beanA的beanFactory,从beanFactory获取beanA的代理对象(如果不需要代理工厂就返回目标对象) 后立马放入二级缓存,然后返回给内部调用者。后续内部获取bean都从二级缓存获取代理对象。
什么情况下不能解决循环依赖?
Spring 如何解决循环依赖 - LARRY1024 - 博客园
- 构造器注入的依赖
因为bean都是需要实例化之后放入三级缓存才能解决问题的。加入现在有A和B互相依赖。
A构造注入B,那么在实例化A时,需要B。去缓存中找,找不到B那么就构造B,由于B也依赖了A,那么需要注入A,这时A并没有实例化完成(因为A的构造方法没调用完毕),所以无法解决循环依赖。
- Bean不为单例时不能解决循环依赖问题
spring里面有很多常用的这些注解。举一两个常用的,以及介绍一下,就是他们实现什么功能,以及它大概是怎么实现的话就更好。(阿里。。。难)
- autowired 和 resources
- bean和configuration
- component、controller、service
- configurationProperties(prefix)
拦截器和过滤器了解么?
都可以对请求进行拦截,统一处理请求。
区别
- 所属范围
-
- 过滤器工作在 Servlet 容器中 , 不由spring管理不能直接获取IOC中的bean。
- 拦截器是Spring提供并管理的,可以获取IOC容器的bean。
- 调用顺序
-
- 过滤器是请求进入servlet之前进行预处理的结束返回也是,是在servlet处理完后,返回给前端之前。
- 拦截器是执行controller方法之前进行拦截。
- 底层实现
-
- 过滤器的实现基于回调函数。
- 拦截器实现是动态代理 基于反射。
- 应用场景
-
-
过滤器 过滤敏感词汇(防止sql注入),我的项目中添加跨域的响应头(修改response) 。
-
拦截器 登录校验、权限校验、日志记录等。
-
这张图很重要,其中包括了filter、dispatcherServlet和拦截器
Spring 动态代理默认用哪一种
spring默认是jdk动态代理,用不了jdk动态代理才会用cglib。
BeanFactoryPostProcessor是干嘛的?(注意不是beanPostProcessor)
BeanFactory创建完成后,所有的Bean初始化之前。调用PostProcessor的PostProcessoBeanfactory方法,通常用于新增BeanDefinition
面试篇-06_前置知识_BeanFactoryPostProcessor_哔哩哔哩_bilibili
转发和重定向的区别?
- 重定向是两次请求,转发是同一次请求。
- 重定向可以让浏览器请求新的url,转发只是服务端将请求转发至 同一服务器 中的资源(前端url不会变)。
- 重定向的状态码是3xx,转发的话任然显示200。