1、什么是Spring? 使用Spring框架的好处是什么(特点)?
Spring 是个Java企业级应用的开源开发框架。旨在降低应用程序开发的复杂度。
Spring框架的特点:
• 轻量:Spring 是轻量的,Spring属于低侵入式设计,代码的污染极低
• 控制反转(IoC):Spring通过控制反转实现了松耦合。 (软件设计中的【耦合】指,两个功能函数之间的依赖程度)
• 面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开
• 容器:Spring 包含并管理应用中对象的生命周期和配置
• MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品
• 事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)
2、Spring由哪些模块组成?
简单可以分成6大模块:
Spring Core spring的核心类库,提供IoC服务;
Spring Web Spring对web模块的支持。
---可以与struts整合,让struts的action创建交给spring
---spring mvc模式
Spring DAO Spring 对JDBC操作的支持 【JdbcTemplate模板工具类】
Spring ORM 对现有的ORM框架的支持;
---既可以与hibernate整合,【session】
---也可以使用spring的对hibernate操作的封装
Spring AOP AOP服务;
SpringEE spring 对javaEE其他模块的支持
核心容器(Core) 模块:
这是基本的Spring模块,提供Spring 框架的基础功能,BeanFactory是任何以Spring为基础的应用的核心。Spring的本质是一个bean工厂(beanFactory)或者说bean容器
3、解释一下什么是 IOC? 什么是Spring的依赖注入?
IoC是Inversion of Control的缩写,大多数翻译成“控制反转”。
IoC理论提出的观点大体是这样的:借助于“第三方”实现具有依赖关系的对象之间的解耦。
对象之间的关系本来是由我们开发者自己创建和维护的,在我们使用Spring框架后,
对象之间的关系由容器来创建和维护,将开发者做的事让容器做,这就是控制反转。
BeanFactory接口是Spring IoC容器的核心接口。
控制反转是目标,依赖注入(DI, Dependency Injection)是我们实现控制反转的一种手段。
最直观的表达就是,IOC让对象的创建不用去new了,可以由spring自动生产,使用java的反射机制,
根据配置文件在运行时动态的去创建对象以及管理对象,并调用对象的方法。
4、 有哪些常用的依赖注入方式?
Spring通过DI(依赖注入)实现IoC(控制反转),常用的注入方式主要有三种:
• setter注入
• 构造方法注入
• 基于注解的注入
5、Spring 中有几种 IoC 容器?以及二者的区别
2种,和是Spring的两大核心接口,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的子接口。
• BeanFactory:是Spring里面最底层的接口,包含了各种bean的定义、读取bean配置文档、
管理bean的加载、实例化、控制bean的生命周期、维护bean之间的依赖关系。
• ApplicationContext接口作为BeanFactory的派生,除了提供BeanFactory所具有的功能外,
还提供了更完整的框架功能:比如提供在监听器中注册bean的事件、同时加载多个配置文件。
6、列举 IoC 的一些好处
• 它将最小化应用程序中的代码量
• 它以最小的影响和最少的侵入机制促进松耦合
7、什么是Spring beans?
Spring bean 表示受到Spring管理的对象。具体说来,它是被Spring框架容器初始化、配置和管理的对象。Spring bean是在Spring的配置文件中定义(以XML文件中<bean/>
的形式定义),在Spring容器中初始化,然后注入到应用程序中的。
8、Spring 有几种配置方式?
Spring主要包括了 3 种配置bean元数据的方式:
• 基于XML文件的配置
bean 所需的依赖项和服务在 XML 格式的配置文件中指定,通常以 <bean> 标签开头。例如:
<bean id="studentbean" class="org.edureka.firstSpring.StudentBean">
<property name="name" value="Edureka"></property>
</bean>
• 基于注解的配置
即Bean的定义信息可以通过在Bean的实现类上标注注解实现。
(@Component 通用注解 [kəmˈpəʊnənt]
@Repository 持久层注解 [rɪˈpɒzətɔːri]
@Service 业务层注解 [ˈsɜːvɪs]
@Controller 控制层注解) [kənˈtroʊlər]
• 基于Java的配置
Spring 的 Java 配置是通过使用 @Bean 和 @Configuration 来实现。[kənˌfɪɡəˈreɪʃn]
9、解释Spring框架中bean的生命周期
• Spring IoC容器从XML 文件中读取bean的定义,并实例化bean
• Spring IoC容器对bean进行依赖注入(设置对象属性)
• 检测该对象是否实现了xxxAware接口
-----如果Bean实现了BeanNameAware接口,则将该bean的id传给setBeanName方法。
-----如果Bean实现了BeanFactoryAware接口,则将BeanFactory对象传给setBeanFactory方法
• 将bean的实例传递给bean前置处理器的postProcessBeforeInitialization方法
• 调用bean的初始化方法 (init-method)
• 将bean的实例传递给bean后置处理器的postProcessAfterInitialization方法
• 使用bean
• 当销毁Bean实例时,如果Bean实现了DisposableBean接口,则调用其destroy方法
10、 Spring 支持几种 bean 的作用域?
作用域的概念:
在面向对象程序设计中作用域一般指对象或变量之间的可见范围。
Spring Bean 中所说的作用域,在Spring容器中是指其创建的bean对象相对于其他bean对象
的请求可见范围。
Spring框架支持以下 5 种bean的作用域类型,在配置文件中,通过属性scope来设置bean的作用域范围。
• singleton(单例模式)[ˈsɪŋɡltən]
当Bean的作用域为singleton的时候,默认,Spring容器中只会存在一个bean实例。
• prototype (原型模式)[ˈprəʊtətaɪp]
是指每次从容器中调用bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行new Bean()的操作
• request
使用该属性定义Bean时,每次HTTP网络请求都会创建一个新的Bean,在请求完成以后,
bean会失效并被垃圾回收器回收。该作用域仅在基于web的SpringApplicationContext情形下有效
• session
该属性仅用于HTTP Session,确保每个session中有一个bean的实例。在session过期后,bean会随之失效。
• global session
该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个bean实例。
缺省的Spring bean 的作用域是Singleton(缺省:系统默认状态)
11、什么是Spring的内部inner bean?
当一个bean仅被用作另一个bean的属性时,它能被声明为一个内部bean
为了定义inner bean,在Spring 的 基于XML的 配置数据中,可以在 <property/>
或 <constructor-arg/>
元素内使用<bean/>
元素,内部bean通常是匿名的,它们的Scope一般是prototype
12、Spring 框架中的单例 beans 是线程安全的么?
在某种程度上说Spring的单例bean是线程安全的。但如果你的bean有多种状态的话(比如 View Model 对象),就需要自行保证线程安全。
最浅显的解决办法就是将多态bean的作用域由 “singleton” 变更为 “prototype”,让每一个线程都能拥有一个实例,这样就不会让多线程并发的时候共同操作一个实例而导致脏数据的问题。
无状态会话bean :bean一旦实例化就被加进会话池中,各个用户都可以共用。
由于没有特定的用户,那么也就不能保持某一用户的状态,所以叫无状态bean
有状态会话bean :每个用户有自己特有的一个实例,在用户的生存期内,bean保持了用户的信息,即“有状态”;
一旦实例结束,bean的生命期也会结束。
13、在 Spring中如何注入一个Java Collection(集合)?
Spring提供以下几种集合的配置元素:
<list>类型用于注入一列值,允许有相同的值
<set> 类型用于注入一组值,不允许有相同的值
<map> 类型用于注入一组键值对,键和值都可以为任意类型
<props>类型用于注入一组键值对,键和值都只能为String类型
14、什么是bean装配? 什么是bean的自动装配?以及Spring 自动装配有哪些方式?
创建对象的协作关系称为装配,也就是DI(依赖注入)的本质。而在Spring容器中对bean的创建时就需要对它所依赖的对象进行注入装配。
Spring bean装配有3种方式:
• 手动装配(通过XML装配bean):
使用到的标签:
<bean>:将类装配为bean,属性id是为bean指定id,class是导入的类
<constructor-arg>:构造器中声明DI,属性value是注入值,ref是注入对象引用。
<property>:设置属性,name是方法中参数名字,ref是注入的对象
• 自动装配:
• 通过Java代码装配bean:
使用到的注解:
@Bean:可以通过name属性自定义id。
@ImportResourse:将指定的XML配置加载进来
@Import:将指定的Java配置加载进来。
手动装配就是要自己给定属性,然后赋值。Spring IOC容器可以自动装配bean,需要做的仅仅是在<bean>
的autowire属性里指定自动装配的模式 。
有 5 种自动装配的方式:
• no:默认的方式是不进行自动装配,通过显式设置ref属性来进行装配
• byName:通过参数名自动装配,之后容器试图匹配、装配和该bean的属性具有相同名字的bean
• byType:通过参数类型自动装配,之后容器试图匹配、装配和该bean的属性具有相同类型的bean。
如果有多个bean符合条件,则抛出错误
• constructor:这个方式类似于byType,但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,
将会抛出异常
• autodetect:首先尝试使用constructor来自动装配,如果无法工作,则使用byType方式。
15、 @Component, @Controller, @Repository, @Service 有何区别?
注解后都可以被Spring框架所扫描并注入到Spring的bean容器中来进行管理,让一个类变成bean。
@Controller 作用于表现层用于标注控制器类(spring-mvc的注解)
@Service 作用于业务逻辑层
@Repository 作用于持久层用于标注DAO类 [rɪˈpɑːzətɔːri]
@Component 最普通的组件,可以被注入到Spring容器进行管理,当我们无法区分这个类属于MVC的那个层次时就可以使用这个注解。
16、谈一谈@Resource(name=“”) 注解,@Autowired 注解,@Require注解和@Qualifier 注解
• @Resource和@Autowired都可以用来装配bean,
-----@Resource默认是按照byName进行装配的
@Autowired默认是按照byType进行装配的
• @Required
-----用于属性的set方法,那么这个属性必须在xml文件的bean标签里面进行配置,否则就会抛出一个
BeanInitializationException异常。
• @Qualifier
-----qualifier意思就是“合格者、候选者”,当有多个相同类型的bean却只有一个需要自动装配时,
将@Qualifier注解和@Autowire 注解结合使用指定需要装配的确切的bean。
17、Spring是如何解决循环依赖问题的?
1.什么是循环依赖?
循环依赖指的是多个对象之间的依赖关系形成一个闭环。
循环依赖会导致的问题:
• 循环依赖会产生多米诺骨牌效应。难以维护,因为互相依赖,你改动一个自然会影响其他依赖对象
• 循环依赖会导致内存溢出
如果此时想对a或b进行赋值操作,那么有2种操作:
• set方法进行赋值
• 创建一个带有参数的构造方法
这2种操作会导致2种循环依赖:
构造器循环依赖(无法解决)
属性注入循环依赖(三级缓存解决)
2.循环依赖怎么解决?
在Spring Framework整个体系中,我们的一个bean是由BeanDefinition来构建的,BeanDefinition可以理解为我们Spring bean的一个建模,要解释循环依赖,首先我们说到Spring bean的生命周期,Spring bean的生命周期大体分为以下几步:
首先Spring 容器启动扫描,把BeanName变成BeanDefinition存到我们的BeanDefinitionMap中进行遍历,遍历完成后对我们的Spring的BeanDefinition做一些基本的验证,包括是否单例,是否懒加载等等。
验证完成后,Spring开始实例化bean前,它会去我们Spring单例池中获取一遍,看bean有没有被创建,如果没有,再去看bean有没有存在我们的二级缓存中,即有没有被提前暴露,如果都没有,我们的代码会继续往下执行
通过反射来实例化X对象后X被提前暴露,暴露的是由X创建出来的ObjectFactory对象(工厂对象),之后对X对象做一些初始化工作,包括填充属性,之后回调aware接口,执行Spring生命周期回调方法,把对象放入单例池容器,最后销毁这个对象,整个就是bean的大致生命周期。
在填充属性时发现X依赖了Y,它就会走Y的生命周期流程,和X一样,首先对Y做验证,判断Y不在单例池中,Y没有被实例化提前暴露,则Y继续往下执行,把Y给实例化好,之后对Y做初始化工作,包括把Y提前暴露(存到三级缓存singletonFactories中),对Y做属性填充(自动注入),当对Y做属性填充是发现要先填充X,这个时候发现X并没有被完整地实例化,不存在于单例池中所以不能填充,再去走一遍创建X的流程,在走X流程过程中,发现X已经被提前暴露(getSingleton这个方法,会依次到一级缓存,二级缓存,三级缓存中get(beanName),很显然当X注入Y属性的时候,一级,二级里面都没有内容,只有三级有,这时会执行lambda表达式,lambda表达式的作用就是生成代理对象!然后把生成的代理对象存入二级缓存,),于是能拿到一个由ObjectFactory所产生的X对象,这样子就完成了循环依赖。
3.Spring循环依赖为什么支持单例?以及为什么解决不了构造方法注入的循环依赖 ?
单例的话会在Spring容器初始化的时候走我们bean的生命流程,而原型的话一开始不会走,只有用到才会走Spring bean的生命流程。
如果X,Y通过构造方法注入的话,即通过X的构造方法、Y的构造方法把X,Y传递进来,由于构造方法不能创建对象,第一次实例化X需要Y,Y没有,实例化Y需要X,X也没有。
18、 Spring支持的事务管理类型
Spring事务的本质其实就是数据库对事务的支持,没有数据库的事务支持,Spring是无法提供事务功能的。 Spring支持两种类型的事务管理:
编程式事务管理:使用TransactionTemplate,在代码中显式调用开启事务、提交事务、回滚事务的相关方法,
带来极大的灵活性,但是难维护。
声明式事务管理:声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的代码,只需在XML配置文件中
做相关的事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中。
大多数Spring框架的用户选择声明式事务管理,因为它对应用代码的影响最小,因此更符合Spring倡导无侵入的轻量级容器的思想。
19、Spring事务的传播行为和隔离级别
事务,是为了保障逻辑处理的原子性、一致性、隔离性、永久性。通过事务控制,可以避免因为逻辑处理失败而导致产生脏数据等一系列的问题。 事务注解方式: @Transactional
事务有两个重要特性:
事务的传播行为
数据隔离级别
事务传播行为(Transaction Behavior):
Spring事务的传播行为说白了就是,当多个事务同时存在的时候,Spring如何处理这些事务的行为。
Spring 中提供的 7 种事务传播行为(propagation 英 [ˌprɒpə'ɡeɪʃ(ə)n]):
• PROPAGATION_REQUIRED:如果当前没有事务,就创建一个新事务,如果当前存在事务,就加入该事务。
这是 Spring 默认的事务传播行为。
• PROPAGATION_SUPPORTS:支持当前事务,如果当前存在事务,就加入该事务,如果当前不存在事务,
则以非事务的方式继续运行
• PROPAGATION_NOT_SUPPORTED:以非事务方式执行操作,如果当前存在事务,就把当前事务挂起
• PROPAGATION_REQUIRES_NEW:创建新事务,无论当前存不存在事务,都创建新事务
• PROPAGATION_NEVER:以非事务方式执行,如果当前存在事务,则抛出异常。
......
事务的隔离级别(Isolation Level):
20、 解释一下AOP?
AOP(Aspect-Oriented Programming,[ˈæspekt]-[ˈɔːrientɪd] [ˈprəʊɡræmɪŋ]), 即面向切面编程, 是OOP(Object-Oriented Programming, 面向对象编程)编程的有效补充。在OOP中最小的单元是类(class),而在AOP中最小的单元是切面(aspect)。
通俗地讲就是,AOP有助于我们将不同但是有必要的重复性代码(比如权限管理,事物管理,日志记录等等)
独立提取出来,独立实现,然后通过切面切入进系统。
这么做的好处是,我们可以将这些重复性代码集中管理起来复用,而不是每次都要重复写一遍。
代码将会变得更易于维护,从而将业务逻辑从杂乱的代码中脱离出来,专注于业务逻辑代码的开发
21、 什么是代理?以及Spring AOP 采用哪种代理?
代理模式的核心作用就是通过代理,控制对对象的访问。
AOP实现的关键在于代理模式,AOP代理主要分为静态代理和动态代理。 静态代理的代表为AspectJ;动态代理则以Spring AOP为代表。
• AspectJ是静态代理,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,
会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。
• Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,
而是每次运行时在内存中临时为方法生成一个AOP对象,
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB(Code Generation Library)动态代理:
• JDK动态代理的核心InvocationHandler接口和Proxy类,如果Proxy代理类实现了InvocationHandler接口
[ˌɪnvəˈkeɪʃn],默认情况下会采用 JDK 的动态代理实现 AOP;
• 如果代理类没有实现 InvocationHandler 接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。
Spring 会自动在 JDK 和 CGLIB 动态代理之间转换。
22、解释一下Spring AOP里面的几个名词:
• 切面(Aspect):被切取的公共模块,可能会横切多个对象。在Spring AOP中,切面可以在普通类中以@AspectJ注解来实现。
• 连接点(Join point):指方法,在Spring AOP中,一个连接点总是代表一个方法的执行。
• 通知(Advice):在切面的某个特定的连接点(Join point)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。
23、Spring通知有哪些类型?
A.前置通知(Beforeadvice):调用目标对象方法之前执行。
B.后置通知(Afterreturning advice):调用目标对象方法之后执行。
C.异常通知(Afterthrowing advice):目标对象方法出错后执行。
D.最终通知(After(finally)advice):目标对象方法出错或者执行完成后执行。
E.环绕通知(AroundAdvice):目标对象方法执行前和执行后都会执行通知。
24、Spring 框架中都用到了哪些设计模式?
• 工厂模式:BeanFactory就是简单工厂模式的体现,用来创建对象的实例;
• 单例模式:Bean默认为单例模式。
• 代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;
• 模板方法:用来解决代码重复的问题。如.RestTemplate,JmsTemplate,JpaTemplate。
• 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,
所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现ApplicationListener
JDK8的新特性:
1.Lambda表达式:Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中。
2.新的日期API: Java 8 在 java.time 包下提供了很多新的 API改进时间、日期的处理。
以下为两个比较重要的 API:
-----Local(本地) − 简化了日期时间的处理,没有时区的问题。
-----Zoned(时区) − 通过制定的时区处理日期时间。
3.接口的默认方法和静态方法:Java 8用默认方法与静态方法这两个新概念来扩展接口的声明。
4.新增Stream类:把真正的函数式编程风格引入到Java中
5.注解相关的改变:
-----注解有一个很大的限制是:在同一个地方不能多次使用同一个注解。
-----Java 8打破了这个限制,引入了重复注解的概念,允许在同一个地方多次使用同一个注解。