本文收录于《面试小抄》系列,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 间依赖关系。
例如:
@Configurationpublic 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。