共计 7879 个字符,预计需要花费 20 分钟才能阅读完成。
本文收录于《面试小抄》系列,Github 地址(可下载 pdf):https://github.com/cosen1024/… 国内 Gitee(可下载 pdf):https://gitee.com/cosen1024/J…
1. 什么是依赖注入?能够通过多少种形式实现依赖注入?
在依赖注入中,您不用创建对象,但必须形容如何创立它们。您不是间接在代码中将组件和服务连贯在一起,而是形容配置文件中哪些组件须要哪些服务。由 IoC 容器将它们拆卸在一起。
通常,依赖注入能够通过三种形式实现,即:
- 构造函数注入
- setter 注入
- 接口注入
在 Spring Framework 中,仅应用构造函数和 setter 注入。
2. 辨别 BeanFactory 和 ApplicationContext?
BeanFactory | ApplicationContext |
---|---|
它应用懒加载 | 它应用即时加载 |
它应用语法显式提供资源对象 | 它本人创立和治理资源对象 |
不反对国际化 | 反对国际化 |
不反对基于依赖的注解 | 反对基于依赖的注解 |
BeanFactory 和 ApplicationContext 的优缺点剖析:
BeanFactory 的优缺点:
- 长处:利用启动的时候占用资源很少,对资源要求较高的利用,比拟有劣势;
- 毛病:运行速度会相对来说慢一些。而且有可能会呈现空指针异样的谬误,而且通过 Bean 工厂创立的 Bean 生命周期会简略一些。
ApplicationContext 的优缺点:
- 长处:所有的 Bean 在启动的时候都进行了加载,零碎运行的速度快;在系统启动的时候,能够发现零碎中的配置问题。
- 毛病:把费时的操作放到系统启动中实现,所有的对象都能够预加载,毛病就是内存占用较大。
3. spring 提供了哪些配置形式?
- 基于 xml 配置
bean 所需的依赖项和服务在 XML 格局的配置文件中指定。这些配置文件通常蕴含许多 bean 定义和特定于应用程序的配置选项。它们通常以 bean 标签结尾。例如:
<bean id="studentbean" class="org.edureka.firstSpring.StudentBean">
<property name="name" value="Edureka"></property>
</bean>
- 基于注解配置
您能够通过在相干的类,办法或字段申明上应用注解,将 bean 配置为组件类自身,而不是应用 XML 来形容 bean 拆卸。默认状况下,Spring 容器中未关上注解拆卸。因而,您须要在应用它之前在 Spring 配置文件中启用它。例如:
<beans>
<context:annotation-config/>
<!-- bean definitions go here -->
</beans>
- 基于 Java API 配置
Spring 的 Java 配置是通过应用 @Bean 和 @Configuration 来实现。
- @Bean 注解表演与
<bean />
元素雷同的角色。 - @Configuration 类容许通过简略地调用同一个类中的其余 @Bean 办法来定义 bean 间依赖关系。
例如:
@Configuration
public class StudentConfig {
@Bean
public StudentBean myStudent() {return new StudentBean();
}
}
4. Spring 中的 bean 的作用域有哪些?
- singleton : 惟一 bean 实例,Spring 中的 bean 默认都是单例的。
- prototype : 每次申请都会创立一个新的 bean 实例。
- request : 每一次 HTTP 申请都会产生一个新的 bean,该 bean 仅在以后 HTTP request 内无效。
- session ::在一个 HTTP Session 中,一个 Bean 定义对应一个实例。该作用域仅在基于 web 的 Spring ApplicationContext 情景下无效。
- global-session:全局 session 作用域,仅仅在基于 portlet 的 web 利用中才有意义,Spring5 曾经没有了。Portlet 是可能生成语义代码 (例如:HTML) 片段的小型 Java Web 插件。它们基于 portlet 容器,能够像 servlet 一样解决 HTTP 申请。然而,与 servlet 不同,每个 portlet 都有不同的会话
5. 如何了解 IoC 和 DI?
IOC 就是管制反转,艰深的说就是咱们不必本人创立实例对象,这些都交给 Spring 的 bean 工厂帮咱们创立治理。这也是 Spring 的核心思想,通过面向接口编程的形式来是实现对业务组件的动静依赖。这就意味着 IOC 是 Spring 针对解决程序耦合而存在的。在理论利用中,Spring 通过配置文件(xml 或者 properties)指定须要实例化的 java 类(类名的残缺字符串),包含这些 java 类的一组初始化值,通过加载读取配置文件,用 Spring 提供的办法(getBean())就能够获取到咱们想要的依据指定配置进行初始化的实例对象。
- 长处:IOC 或依赖注入缩小了应用程序的代码量。它使得应用程序的测试很简略,因为在单元测试中不再须要单例或 JNDI 查找机制。简略的实现以及较少的烦扰机制使得松耦合得以实现。IOC 容器反对勤性单例及提早加载服务。
DI:DI—Dependency Injection,即“依赖注入”:组件之间依赖关系由容器在运行期决定,形象的说,即由容器动静的将某个依赖关系注入到组件之中。依赖注入的目标并非为软件系统带来更多功能,而是为了晋升组件重用的频率,并为零碎搭建一个灵便、可扩大的平台。通过依赖注入机制,咱们只须要通过简略的配置,而无需任何代码就可指定指标须要的资源,实现本身的业务逻辑,而不须要关怀具体的资源来自何处,由谁实现。
6. 将一个类申明为 Spring 的 bean 的注解有哪些?
咱们个别应用 @Autowired 注解主动拆卸 bean,要想把类标识成可用于 @Autowired 注解主动拆卸的 bean 的类, 采纳以下注解可实现:
- @Component:通用的注解,可标注任意类为 Spring 组件。如果一个 Bean 不晓得属于哪个层,能够应用 @Component 注解标注。
8 @Repository : 对应长久层即 Dao 层,次要用于数据库相干操作。 - @Service : 对应服务层,次要波及一些简单的逻辑,须要用到 Dao 层。
- @Controller : 对应 Spring MVC 管制层,次要用户承受用户申请并调用 Service 层返回数据给前端页面。
7. Spring 中的 bean 生命周期?
Bean 的生命周期是由容器来治理的。次要在创立和销毁两个期间。
创立过程:
1,实例化 bean 对象,以及设置 bean 属性;
2,如果通过 Aware 接口申明了依赖关系,则会注入 Bean 对容器基础设施层面的依赖,Aware 接口是为了感知到本身的一些属性。容器治理的 Bean 个别不须要晓得容器的状态和间接应用容器。然而在某些状况下是须要在 Bean 中对 IOC 容器进行操作的。这时候须要在 bean 中设置对容器的感知。SpringIOC 容器也提供了该性能,它是通过特定的 Aware 接口来实现的。
比方 BeanNameAware 接口,能够晓得本人在容器中的名字。
如果这个 Bean 曾经实现了 BeanFactoryAware 接口,能够用这个形式来获取其它 Bean。
(如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName()办法,传入 Bean 的名字。
如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader()办法,传入 ClassLoader 对象的实例。
如果 Bean 实现了 BeanFactoryAware 接口,调用 setBeanFactory()办法,传入 BeanFactory 对象的实例。)
3,紧接着会调用 BeanPostProcess 的前置初始化办法 postProcessBeforeInitialization,次要作用是在 Spring 实现实例化之后,初始化之前,对 Spring 容器实例化的 Bean 增加自定义的解决逻辑。有点相似于 AOP。
4,如果实现了 BeanFactoryPostProcessor 接口的 afterPropertiesSet 办法,做一些属性被设定后的自定义的事件。
5,调用 Bean 本身定义的 init 办法,去做一些初始化相干的工作。
6,调用 BeanPostProcess 的后置初始化办法,postProcessAfterInitialization 去做一些 bean 初始化之后的自定义工作。
7,实现以上创立之后就能够在利用里应用这个 Bean 了。
销毁过程:
当 Bean 不再用到,便要销毁
1,若实现了 DisposableBean 接口,则会调用 destroy 办法;
2,若配置了 destry-method 属性,则会调用其配置的销毁办法;
总结
次要把握创立过程和销毁过程这两个大的方面;
创立过程:首先实例化 Bean,并设置 Bean 的属性,依据其实现的 Aware 接口(次要是 BeanFactoryAware 接口,BeanFactoryAware,ApplicationContextAware)设置依赖信息,
接下来调用 BeanPostProcess 的 postProcessBeforeInitialization 办法,实现 initial 前的自定义逻辑;afterPropertiesSet 办法做一些属性被设定后的自定义的事件; 调用 Bean 本身定义的 init 办法,去做一些初始化相干的工作; 而后再调用 postProcessAfterInitialization 去做一些 bean 初始化之后的自定义工作。这四个办法的调用有点相似 AOP。
此时,Bean 初始化实现,能够应用这个 Bean 了。
销毁过程:如果实现了 DisposableBean 的 destroy 办法,则调用它,如果实现了自定义的销毁办法,则调用之。
8. 什么是 AOP?
AOP(Aspect-Oriented Programming), 即 面向切面编程 , 它与 OOP(Object-Oriented Programming, 面向对象编程) 相辅相成, 提供了与 OOP 不同的形象软件结构的视角.
在 OOP 中, 咱们以类 (class) 作为咱们的根本单元, 而 AOP 中的根本单元是 Aspect(切面)
9. AOP 有哪些实现形式?
实现 AOP 的技术,次要分为两大类:
-
动态代理 – 指应用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因而也称为编译时加强;
- 编译时编织(非凡编译器实现)
- 类加载时编织(非凡的类加载器实现)。
-
动静代理 – 在运行时在内存中“长期”生成 AOP 动静代理类,因而也被称为运行时加强。
JDK
动静代理:通过反射来接管被代理的类,并且要求被代理的类必须实现一个接口。JDK 动静代理的外围是 InvocationHandler 接口和 Proxy 类。CGLIB
动静代理:如果指标类没有实现接口,那么Spring AOP
会抉择应用CGLIB
来动静代理指标类。CGLIB
(Code Generation Library),是一个代码生成的类库,能够在运行时动静的生成某个类的子类,留神,CGLIB
是通过继承的形式做的动静代理,因而如果某个类被标记为final
,那么它是无奈应用CGLIB
做动静代理的。
10. Spring AOP and AspectJ AOP 有什么区别?
Spring AOP 基于动静代理形式实现;AspectJ 基于动态代理形式实现。
Spring AOP 仅反对办法级别的 PointCut;提供了齐全的 AOP 反对,它还反对属性级别的 PointCut。
11. Spring 中呈现同名 bean 怎么办?
- 同一个配置文件内同名的 Bean,以最下面定义的为准
- 不同配置文件中存在同名 Bean,后解析的配置文件会笼罩先解析的配置文件
- 同文件中 ComponentScan 和 @Bean 呈现同名 Bean。同文件下 @Bean 的会失效,@ComponentScan 扫描进来不会失效。通过 @ComponentScan 扫描进来的优先级是最低的,起因就是它扫描进来的 Bean 定义是最先被注册的~
12. Spring 怎么解决循环依赖问题?
spring 对循环依赖的解决有三种状况:
①结构器的循环依赖:这种依赖 spring 是解决不了的,直 接抛出 BeanCurrentlylnCreationException 异样。
②单例模式下的 setter 循环依赖:通过“三级缓存”解决循环依赖。
③非单例循环依赖:无奈解决。
上面剖析单例模式下的 setter 循环依赖如何解决
Spring 的单例对象的初始化次要分为三步:
(1)createBeanInstance:实例化,其实也就是调用对象的构造方法实例化对象
(2)populateBean:填充属性,这一步次要是多 bean 的依赖属性进行填充
(3)initializeBean:调用 spring xml 中的 init 办法。
从下面讲述的单例 bean 初始化步骤咱们能够晓得,循环依赖次要产生在第一、第二部。也就是结构器循环依赖和 field 循环依赖。
A 的某个 field 或者 setter 依赖了 B 的实例对象,同时 B 的某个 field 或者 setter 依赖了 A 的实例对象”这种循环依赖的状况。A 首先实现了初始化的第一步(createBeanINstance 实例化),并且将本人提前曝光到 singletonFactories 中,此时进行初始化的第二步,发现自己依赖对象 B,此时就尝试去 get(B),发现 B 还没有被 create,所以走 create 流程,B 在初始化第一步的时候发现自己依赖了对象 A,于是尝试 get(A),尝试一级缓存 singletonObjects(必定没有,因为 A 还没初始化齐全),尝试二级缓存 earlySingletonObjects(也没有),尝试三级缓存 singletonFactories,因为 A 通过 ObjectFactory 将本人提前曝光了,所以 B 可能通过 ObjectFactory.getObject 拿到 A 对象(尽管 A 还没有初始化齐全,然而总比没有好呀),B 拿到 A 对象后顺利完成了初始化阶段 1、2、3,齐全初始化之后将本人放入到一级缓存 singletonObjects 中。此时返回 A 中,A 此时能拿到 B 的对象顺利完成本人的初始化阶段 2、3,最终 A 也实现了初始化,进去了一级缓存 singletonObjects 中,而且更加侥幸的是,因为 B 拿到了 A 的对象援用,所以 B 当初 hold 住的 A 对象实现了初始化。
13. SpringMVC 工作原理理解吗?
原理如下图所示:
上图的一个笔误的小问题:Spring MVC 的入口函数也就是前端控制器 DispatcherServlet
的作用是接管申请,响应后果。
流程阐明(重要):
- 客户端(浏览器)发送申请,间接申请到
DispatcherServlet
。 DispatcherServlet
依据申请信息调用HandlerMapping
,解析申请对应的Handler
。- 解析到对应的
Handler
(也就是咱们平时说的Controller
控制器)后,开始由HandlerAdapter
适配器解决。 HandlerAdapter
会依据Handler
来调用真正的处理器开解决申请,并解决相应的业务逻辑。- 处理器解决完业务后,会返回一个
ModelAndView
对象,Model
是返回的数据对象,View
是个逻辑上的View
。 ViewResolver
会依据逻辑View
查找理论的View
。DispaterServlet
把返回的Model
传给View
(视图渲染)。- 把
View
返回给请求者(浏览器)
14. Spring 框架中用到了哪些设计模式?
工厂设计模式 : Spring 应用工厂模式通过 BeanFactory
、ApplicationContext
创立 bean 对象。
代理设计模式 : Spring AOP 性能的实现。
单例设计模式 : Spring 中的 Bean 默认都是单例的。
模板办法模式 : Spring 中 jdbcTemplate
、hibernateTemplate
等以 Template 结尾的对数据库操作的类,它们就应用到了模板模式。
包装器设计模式 : 咱们的我的项目须要连贯多个数据库,而且不同的客户在每次拜访中依据须要会去拜访不同的数据库。这种模式让咱们能够依据客户的需要可能动静切换不同的数据源。
观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个利用。
适配器模式 :Spring AOP 的加强或告诉(Advice) 应用到了适配器模式、spring MVC 中也是用到了适配器模式适配Controller
。
15. Spring 事务实现形式有哪些?
- 编程式事务管理:这意味着你能够通过编程的形式治理事务,这种形式带来了很大的灵活性,但很难保护。
- 申明式事务管理:这种形式意味着你能够将事务管理和业务代码拆散。你只须要通过注解或者 XML 配置管理事务。
16. spring 事务定义的流传规定
- PROPAGATION_REQUIRED: 反对以后事务,如果以后没有事务,就新建一个事务。这是最常见的抉择。
- PROPAGATION_SUPPORTS: 反对以后事务,如果以后没有事务,就以非事务形式执行。
- PROPAGATION_MANDATORY: 反对以后事务,如果以后没有事务,就抛出异样。
- PROPAGATION_REQUIRES_NEW: 新建事务,如果以后存在事务,把以后事务挂起。
- PROPAGATION_NOT_SUPPORTED: 以非事务形式执行操作,如果以后存在事务,就把以后事务挂起。
- PROPAGATION_NEVER: 以非事务形式执行,如果以后存在事务,则抛出异样。
- PROPAGATION_NESTED: 如果以后存在事务,则在嵌套事务内执行。如果以后没有事务,则进行与 PROPAGATION_REQUIRED 相似的操作。
17 .Spring 中的单例 bean 的线程平安问题?
当多个用户同时申请一个服务时,容器会给每一个申请调配一个线程,这时多个线程会并发执行该申请对应的业务逻辑(成员办法),此时就要留神了,如果该解决逻辑中有对单例状态的批改(体现为该单例的成员属性),则必须思考线程同步问题。
线程平安问题都是由全局变量及动态变量引起的。
若每个线程中对全局变量、动态变量只有读操作,而无写操作,一般来说,这个全局变量是线程平安的;若有多个线程同时执行写操作,个别都须要思考线程同步,否则就可能影响线程平安.
无状态 bean 和有状态 bean
- 有状态就是有数据存储性能。有状态对象(Stateful Bean),就是有实例变量的对象,能够保留数据,是非线程平安的。在不同办法调用间不保留任何状态。
- 无状态就是一次操作,不能保留数据。无状态对象(Stateless Bean),就是没有实例变量的对象 . 不能保留数据,是不变类,是线程平安的。
在 spring 中无状态的 Bean 适宜用不变模式,就是单例模式,这样能够共享实例进步性能。有状态的 Bean 在多线程环境下不平安,适宜用 Prototype 原型模式。
Spring 应用 ThreadLocal 解决线程平安问题。如果你的 Bean 有多种状态的话(比方 View Model 对象),就须要自行保障线程平安。
这里也举荐一个我收集的计算机书籍仓库,仓库目前有上百本经典 cs 电子书,看经典的书籍会更悟得深~
点此链接即可中转书单,计算机必看经典书籍(含 pdf 下载)
Github 也有相应仓库,https://github.com/cosen1024/…
欢送 star。