文章目录
1. Spring是什么
Spring是一个轻量级的IOC和AOP的容器框架。主要作用是解决企业应用开发的复杂性,提供主流框架的集成以及对象的统一管理等功能。
2. Spring的优点
- 对代码低侵入性,低污染,且可以自主选择使用Spring的部分功能
- 集合了主流的框架,使开发人员开发更为方便
- 通过依赖注入降低了业务对象替换的复杂性
- 通过AOP技术,可将重复的代码抽离出来,提升代码的可维护性
3. Spring的AOP理解
AOP是面向切面编程,将代码中重复的逻辑进行抽离,作为一个切面统一处理,提高代码的可维护性,主要的应用场景为事务,日志打印,权限校验等。
- AOP分类
- AspectJ
- 实现方式:是静态代理,在编译器直接将切面的代码织如字节码中,实现切面的功能
- 优点:在编译器织入,性能较好
- 缺点:需要特定的编译器
- Spring AOP
- JDK动态代理:通过写入一个代理类的字节码文件,该代理类的构造方法中传入了用户实现的InvocationHandler接口的代理对象,在调用代理对象的方法时,会调用接口实现的invoke方法,并将代理类和方法及参数传给Invoke方法;被代理类需要实现一个接口,原因是基于接口进行代理
- CGLIB动态代理:通过生成被代理类的子类代理对象,在代理类中加入调用拦截器的增强方法实现;被代理类不能是final的,原因是需要通过构造子类代理对象实现
- 优点:无需特定的编译器
- 缺点:性能相对静态代理慢
- AspectJ
一张图看懂jdk动态代理机制
一张图看懂cglib动态代理机制
4. Spring的IOC的理解
- IOC:叫做控制反转,就是将对象的创建权交给容器,用户无需自己创建对象,只需在配置文件中配置或者加入注解即可,容器会通过反射的方式创建对象,并加入到容器中,用户可从容器中获取
- DI:就是将容器中的对象赋值给需要调用对象
- 依赖注入方式
- 根据属性注入
- 根据构造器注入
- 根据注解注入
5. BeanFactory和ApplicationContext有什么区别
- BeanFactory:是Spring的最底层接口
- ApplicationContext:1.所有的Bean在容器启动时就会一次性加载,若存在配置错误,可直接排查,较为方便,但是不足是更占用内存空间;2.是BeanFactory的子接口;3.相对来说有更多的功能,如Web、AOP、国际化以及事件机制等。
6. bean的作用域
- singleton:这是默认的,单例模式
- prototype:每次请求就有一个实例
- request:每一次request请求一个实例
- session:每一个session一个实例
- gloab-session:全局的session下一个实例
7. Spring如何保证线程安全
- 将bean的作用域配置成prototype,每次获取bean都是一个对象,从而保证线程安全
- 使用ThreadLocal变量,每个线程使用该变量时,只会使用本线程的变量值,也就是每个线程都有一个该变量的副本,通过空间换取时间
8. Spring中使用的设计模式
- 代理模式——AOP
- 工厂模式——BeanFactory
- 单例模式——bean的单例作用域
- 模板模式——JmsTemplate,RedisTemplate
- 依赖注入——IOC
9. 事务的传播行为
事务的传播行为是调用一个方法后,被调用的方法的事务改如何操作
- PROPAGATION_REQUIRED:被调用的方法有事务就用,没有就创建
- PROPAGATION_REQUIRES_NEW:被调用的方法不管有没有事务,都创建一个事物(使用场景为:不希望外部事物影响内部的事务)
- PROPAGATION_SUPPORTS:被调用的方法有事务就用,没有就挂起
- PROPAGATION_MANDATORY:被调用的方法有事务就用,没有就报错
- PROPAGATION_NOT_SUPPORTED:被调用的方法有事务就挂起,没有也没有事务
- PROPAGATION_NEVER:被调用的方法有事务就报错,没有就没有事务执行
- PROPAGATION_NESTED:被调用的方法有事务就嵌套事务执行,没有就创建一个事务
注:PROPAGATION_REQUIRES_NEW与PROPAGATION_NESTED区别:
- PROPAGATION_REQUIRES_NEW 不会被外部事物影响(若内部事务失败,外部事物可通过catch方式自行决定是否回滚,下同)
methodA PROPAGATION_REQUIRED
methodB PROPAGATION_REQUIRES
1. 若A回滚,B可以成功执行
2. 若B回滚,A catch异常可自行决定是否回滚,可作为分支处理(不推荐)
- PROPAGATION_NESTED 外部事物失败,嵌套的事务必定失败
methodA PROPAGATION_REQUIRED
methodB PROPAGATION_NESTED
1. 若A回滚,B一定回滚
2. 若B回滚,A catch异常可自行决定是否回滚,可作为分支处理(不推荐)
10. Spring AOP中的名词解释
- 切面:日志、权限、事务等框架
- 通知:切面中的方法
- 切入点:切入的条件,符合条件,才能加入通知
- 织入:形成代理类的过程
11. spring5.0新特性
- 升级到jdk8,兼容jdk9
- 支持函数式编程
- 支持响应式编程
12. Spring Bean的生命周期
-
实例化Bean:
对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。
-
设置对象属性(依赖注入):
实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。
-
处理Aware接口:
接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:
3.1 如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;
3.2 如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。
3.3 如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;
-
BeanPostProcessor:
如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。
-
InitializingBean 与 init-method:
如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。
-
如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;
以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。
-
DisposableBean:
当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;
-
destroy-method:
最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。
13. Spring 循环依赖解决
- 构造器循环依赖(无法解决)
- prototype范围的依赖(无法解决)
- 属性注入的单例依赖(可以解决)
- A 创建过程中需要 B,于是 A 将自己放到三级缓里面 ,去实例化 B
- B 实例化的时候发现需要 A,于是 B 先查一级缓存,没有,再查二级缓存,还是没有,再查三级缓存,找到了!
- 然后把三级缓存里面的这个 A 放到二级缓存里面,并删除三级缓存里面的 A
- B 顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态)
- 然后回来接着创建 A,此时 B 已经创建结束,直接从一级缓存里面拿到 B ,然后完成创建,并将自己放到一级缓存里面
Spring 如何解决循环依赖的问题