史上最详细的Spring⾯试题(附答案)
1、简单介绍⼀下Spring?
Spring 是个java企业级应⽤的开源开发框架。Spring主要⽤来开发Java应⽤,但是有些扩展是针对构建J2EE平台的web应⽤。Spring 框架⽬标是简化Java企业级应⽤开发,并通过POJO为基础的编程模型促进良好的编程习惯。
Spring是⼀个轻量级的IoC和AOP容器框架。是为Java应⽤程序提供基础性服务的⼀套框架,⽬的是⽤于简化企业应⽤程序的开发,它使得开发者只需要关⼼业务需求。常见的配置⽅式有三种:基于XML的配置、基于注解的配置、基于Java的配置。
主要由以下⼏个模块组成:
Spring Core:核⼼类库,提供IOC服务;
Spring Context:提供框架式的Bean访问⽅式,以及企业级功能(JNDI、定时任务等);
Spring AOP:AOP服务;
Spring DAO:对JDBC的抽象,简化了数据访问异常的处理;
Spring ORM:对现有的ORM框架的⽀持;
Spring Web:提供了基本的⾯向Web的综合特性,例如多⽅⽂件上传;
Spring MVC:提供⾯向Web应⽤的Model-View-Controller实现。spring ioc注解
2、Spring有哪些优点?
(1)spring属于低侵⼊式设计,代码的污染极低;
(2)spring的DI机制将对象之间的依赖关系交由框架处理,减低组件的耦合性;
(3)Spring提供了AOP技术,⽀持将⼀些通⽤任务,如安全、事务、⽇志、权限等进⾏集中式管理,从⽽提供更好的复⽤。
(4)spring对于主流的应⽤框架提供了集成⽀持。
(1)轻量:Spring 是轻量的,基本的版本⼤约2MB。
(2)控制反转:Spring通过控制反转实现了松散耦合。
(3)⾯向切⾯的编程(AOP):Spring⽀持⾯向切⾯的编程,并且把应⽤业务逻辑和系统服务分开。
(4)容器:Spring 包含并管理应⽤中对象的⽣命周期和配置。
(5)MVC框架:Spring的WEB框架是个精⼼设计的框架,是Web框架的⼀个很好的替代品。
(6)事务管理:Spring 提供⼀个持续的事务管理接⼝,可以扩展到上⾄本地事务,下⾄全局事务(JTA)。
(7)异常处理:Spring 提供⽅便的API把具体技术相关的异常(⽐如由JDBC,Hibernate or JDO抛出的)转化为⼀致的unchecked 异常。
3、讲⼀讲对Spring中的AOP技术的理解
OOP⾯向对象其中⼀个优势就是继承,⽗类的代码可以被⼦类所复⽤,但平级关系类中使⽤相同的功能代码时会出现⼤量代码的重复,不利于各个模块的复⽤,这种情况可以使⽤AOP技术来解决。
AOP称为⾯向切⾯编程,作为⾯向对象的⼀种补充,⽤于将那些与业务⽆关,但却对多个对象产⽣影响的那些公共⾏为和逻辑进⾏抽取并封装为⼀个可重⽤的模块,这个模块被命名为“切⾯(Aspect)”。切⾯可以减少系统中的重复代码,降低模块间的耦合度,同时提⾼系统的可维护性。可⽤于权限认证、⽇志、事务处理。
AOP(Aspect Oriented Programming),即⾯向切⾯编程,可以说是OOP(Object Oriented Programming,⾯向对象编程)的补充和完善。OOP引⼊封装、继承、多态等概念来建⽴⼀种对象层次结构,⽤于模拟公共⾏为的⼀个集合。不过OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如⽇志功能。⽇志代码往往横向地散布在所有对象层次中,⽽与它对应的对象的核⼼功能毫⽆关系对于其他类型的代码,如安全性、异常处理和透明的持续性也都是如此,这种散布在各处的⽆关的代码被称为横切(cross cutting),在OOP设计中,它导致了⼤量代码的重复,⽽不利于各个模块的重⽤。
AOP技术恰恰相反,它利⽤⼀种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共⾏为封装到⼀个可重⽤模块,并将其命名为"Aspect",即切⾯。所谓"切⾯",简单说就是那些与业务⽆关,却为业务模块所共同调⽤的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。
使⽤"横切"技术,AOP把软件系统分为两个部分:
核⼼关注点和横切关注点。业务处理的主要流程是核⼼关注点,与之关系不⼤的部分是横切关注点。横切关注点的⼀个特点是,他们经常发⽣在核⼼关注点的多处,⽽各处基本相似,⽐如权限认证、⽇志、事物。AOP的作⽤在于分离系统中的各种关注点,将核⼼关注点和横切关注点分离开来。
4、介绍⼀下使⽤JDK Proxy类如何实现动态代理?
有业务接⼝,有实现业务接⼝的业务类,还需要创建实现了InvocationHandler接⼝的MyInvocationHandler类。
InvocationHandler 的 invoke(Object proxy,Method method,Object[] args):proxy是最终⽣成的代理实例; method 是被代理⽬标实例的某个具体⽅法; args 是被代理⽬标实例某个⽅法的具体⼊参, 在⽅法反射调⽤时使⽤。
使⽤如下代码创建代理类:
(B)Spring AOP使⽤的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,⽽是每次运⾏时在内存中临时为⽅法⽣成⼀个AOP对象,这个AOP对象包含了⽬标对象的全部⽅法,并且在特定的切点做了增强处理,并回调原对象的⽅法。动态代理可以使⽤JDK Proxy和CGLIB来实现。
回答思路可以先介绍静态代理的缺点,再介绍动态代理的优点。
(C)静态代理与动态代理区别在于⽣成AOP代理对象的时机不同。静态代理在编译时创建了代理类,⽽动态代理是在运⾏时创建了代理类。
6、当业务类实现或未实现接⼝时,在创建代理类时的区别是什么?
① 实现接⼝:JDK动态代理只⽀持对接⼝进⾏代理,不⽀持对类进⾏代理。核⼼内容是InvocationHandler接⼝和Proxy
类,InvocationHandler 通过在invoke()⽅法中使⽤反射技术调⽤⽬标类中的代码,动态地将横切逻辑和业务编织在⼀起;接着,Proxy利⽤ InvocationHandler动态创建⼀个符合某⼀接⼝的的实例, ⽣成⽬标类的代理对象。
② 未实现接⼝:如果业务类没有实现接⼝,那么Spring AOP会选择使⽤CGLIB实现动态代理,代理类继承⾃业务类。CGLIB(Code Generation Library),是⼀个代码⽣成的类库,可以在运⾏时动态的⽣成指定类的⼀个⼦类对象,并覆盖其中特定⽅法并添加增强代码,从⽽实现AOP。CGLIB是通过继承的⽅式做的动态代理,因此如果某个类被标记为final,那么它是⽆法使⽤CGLIB做动态代理的。
7、介绍⼀下对Spring IoC的理解:
(1)IOC是控制反转,是指创建对象的控制权的转移,以前创建对象的主动权和时机是由⾃⼰把控的,
⽽现在这种权⼒转移到Spring容器中,并由容器根据配置⽂件去创建实例和管理各个实例之间的依赖关系,对象与对象之间松散耦合,也利于功能的复⽤。DI依赖注⼊和IOC 控制反转是同⼀个概念的不同⾓度的描述,即:应⽤程序在运⾏时依赖IoC容器来动态注⼊对象需要的外部资源。
(2)最直观的表达就是,IOC让对象的创建不⽤去new了,可以由spring⾃动⽣产,使⽤java的反射机制,根据配置⽂件在运⾏时动态的去创建对象以及管理对象,并调⽤对象的⽅法的。
(3)Spring的IOC有三种注⼊⽅式 :构造器注⼊、setter⽅法注⼊、根据注解注⼊。
IoC让相互协作的组件保持松散的耦合,⽽AOP编程允许你把遍布于应⽤各层的功能分离出来形成可重⽤的功能组件。
IoC不是什么技术,⽽是⼀种设计思想。在java的开发过程中。ioc意味着将你设计好的对象交给容器控制,⽽不是传统的在对象内部直接控制。理解“谁控制谁,控制什么,为何是反转(有反转是不是有正转),反转了哪些”
谁控制谁,控制什么:传统java se程序设计,我们直接在对象内部通过new进⾏创建对象;⽽IOC有专门的容器创建对象,由容器来控制对象;谁控制谁?IOC容器控制对象;控制了什么?主要控制了外部资源获取(不只是对象,包括⽂件)
为何是反转,哪些反转了:有反转就有正转,传统的应⽤程序是由我们在对象中主动控制去直接获取依赖对象,也就是正转;反转就是由容器帮我们创建以及注⼊依赖对象;为何是反转,因为是由容器帮我们查及注⼊对象,对象只是被动的接受;
哪些反转了:依赖对象的获取⽅式被反转了
IOC是⼀种设计思想(思想的转变),之前所有创建对象的操作是由程序员⾃⼰new,现在交给了spring,由spring帮我们创建对象,注⼊之类的。控制反转,控制是指 ioc提供的容器控制类的对象,反转是指转交给spring来负责。最⼤的作⽤就是解耦(降低耦合性)
IOC是⼀种叫做“控制反转”的设计思想。
1、较浅的层次——从名字上解析
“控制”就是指对 对象的创建、维护、销毁等⽣命周期的控制,这个过程⼀般是由我们的程序去主动控制的,如使⽤new关键字去创建⼀个对象(创建),在使⽤过程中保持引⽤(维护),在失去全部引⽤后由GC去回收对象(销毁)。
“反转”就是指对 对象的创建、维护、销毁等⽣命周期的控制由程序控制改为由IOC容器控制,需要某个对象时就直接通过名字去IOC容器中获取。
2、更深的层次——提到DI,依赖注⼊,是IOC的⼀种重要实现
⼀个对象的创建往往会涉及到其他对象的创建,⽐如⼀个对象A的成员变量持有着另⼀个对象B的引⽤,这就是依赖,A依赖于B。IOC机制既然负责了对象的创建,那么这个依赖关系也就必须由IOC容器负责起来。负责的⽅式就是DI——依赖注⼊,通过将依赖关系写⼊配置⽂件,然后在创建有依赖关系的对象时,由IOC容器注⼊依赖的对象,如在创建A时,检查到有依赖关系,IOC容器就把A依赖的对象B创建后注⼊到A中(组装,通过反射机制实现),然后把A返回给对象请求者,完成⼯作。
3、IOC的意义何在?
IOC并没有实现更多的功能,但它的存在使我们不需要很多代码、不需要考虑对象间复杂的耦合关系就能从IOC容器中获取合适的对象,⽽且提供了对 对象的可靠的管理,极⼤地降低了开发的复杂性。
8、BeanFactory和ApplicationContext有什么区别?
BeanFactory和ApplicationContext是Spring的两⼤核⼼接⼝,都可以当做Spring的容器。其中ApplicationContext是BeanFactory的⼦接⼝。
(1)两者具有继承关系
BeanFactory:是Spring⾥⾯最底层的接⼝,包含了各种Bean的定义,读取bean配置⽂档,管理bean的加载、实例化,控制bean的⽣命周期,维护bean之间的依赖关系。ApplicationContext接⼝作为BeanFactory的⼦接⼝,除了提供BeanFactory所具有的功能外,还提供了更完整的框架功能:
A.继承MessageSource,因此⽀持国际化。
B.统⼀的资源⽂件访问⽅式。
C.提供在中注册bean的事件。
D.同时加载多个配置⽂件。
E.载⼊多个(有继承关系)上下⽂ ,使得每⼀个上下⽂都专注于⼀个特定的层次,⽐如应⽤的web层。
(2)两者实例化类的时机不同
A.BeanFactroy采⽤的是延迟加载形式来注⼊Bean的,即只有在使⽤到某个Bean时(调⽤getBean()),才对该Bean进⾏加载实例化。这样,我们就不能发现⼀些存在的Spring的配置问题。如果Bean的某⼀个属性没有注⼊,BeanFacotry加载后,直⾄第⼀次使⽤调⽤getBean⽅法才会抛出异常。
B.ApplicationContext,它是在容器启动时,⼀次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注⼊。 ApplicationContext启动后预载⼊所有的单实例Bean,通过预载⼊单实例bean ,确保当你需要的时候,你就不⽤等待,因为它们已经创建好了。
C.相对于基本的BeanFactory,ApplicationContext 唯⼀的不⾜是占⽤内存空间。当应⽤程序配置Bean较多时,程序启动较慢。
(3)BeanFactory通常以⼿写代码的⽅式被创建。
ApplicationContext还能以声明的⽅式创建,如使⽤ContextLoader,在l中进⾏配置,代码如下:
org.t.ContextLoaderListener
继承关系:
public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
(4)BeanFactory和ApplicationContext都⽀持BeanPostProcessor、BeanFactoryPostProcessor的使⽤,但两者之间的区别是:BeanFactory需要⼿动注册,代码如下:
DefaultListableBeanFactory c;
c.addBeanPostProcessor(beanPostProcessor);
⽅法为public:
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor)
ApplicationContext则是⾃动注册。
public abstract class AbstractApplicationContext extends DefaultResourceLoader
implements ConfigurableApplicationContext {
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
}
BeanFactory:
是spring⾥⾯最底层的接⼝,提供了最简单的容器的功能,只提供实例化对象和获取对象
applicationContext:
应⽤上下⽂,继承了BeanFactory接⼝(上⼀个的⼦接⼝),提供了更多的功能
1.ClassPathXmlApplicationContext 从 classpath 加载 spring 的配置⽂件
2.FileSystemApplicationContext 从系统⽂件加载 spring 的配置⽂件
3.AnnotationConfigApplicationContext 获取基于注解的 spring 容器对象
4.XmlWebApplicationContext 在web环境中获取 spring 容器对象
其中⽐较常⽤的是singleton和prototype两种作⽤域。对于singleton作⽤域的Bean,每次请求该Bean都将获得相同的实例。容器负责跟踪Bean实例的状态,负责维护Bean实例的⽣命周期⾏为;如果⼀个Bean被设置成prototype作⽤域,程序每次请求该id的Bean,Spring 都会新建⼀个Bean实例,然后返回给程序。在这种情况下,Spring容器仅仅使⽤new 关键字创建Bean实例,⼀旦创建成功,容器不在跟踪实例,也不会维护Bean实例的状态。
  如果不指定Bean的作⽤域,Spring默认使⽤singleton作⽤域。Java在创建Java实例时,需要进⾏内存申请;销毁实例时,需要完成垃圾回收,这些⼯作都会导致系统开销的增加。因此,prototype作⽤域Bean的创建、销毁代价⽐较⼤。⽽singleton作⽤域的Bean实例⼀旦创建成功,可以重复使⽤。因此,除⾮必要,否则尽量避免将Bean被设置成prototype作⽤域。
当定义⼀个 在Spring⾥,可以给这个bean声明⼀个作⽤域。通过bean 定义的scope属性来定义。例如当Spring要在需要的时候每次⽣产⼀个新的bean实例,bean的scope属性被指定为prototype。另⼀⽅⾯,⼀个bean每次使⽤的时候必须返回同⼀个实例,这个bean的scope 属性必须设为 singleton。默认是singleton。
11、Spring框架中的单例Beans是线程安全的么?
不⼀定,因为安全与不安全取决于Bean的写法。
Spring框架并没有对单例bean进⾏任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者⾃⾏去搞定。但实际上,⼤部分的Spring bean并没有可变的状态(⽐如Service类和DAO类),所以在某种程度上说Spring的单例bean是线程安全的。如果你的bean有多种状态的话(⽐如 View Model 对象),就需要⾃⾏保证线程安全。最浅显的解决办法就是将多态bean的作⽤域由“singleton”变更为“prototype”。
12、Spring如何处理线程并发问题?
在⼀般情况下,只有⽆状态的Bean才可以在多线程环境下共享,在Spring中,绝⼤部分Bean都可以声明为singleton作⽤域,因为Spring 对⼀些Bean中⾮线程安全状态采⽤ThreadLocal进⾏处理,解决线程安全问题。
ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采⽤了“时间换空间”的⽅式,仅提供⼀份变量,不同的线程在访问前需要获取锁,没获得锁的线程则需要排队。⽽ThreadLocal采⽤了“空间换时间”的⽅式。
ThreadLocal会为每⼀个线程提供⼀个独⽴的变量副本,从⽽隔离了多个线程对数据的访问冲突。因为每⼀个线程都拥有⾃⼰的变量副本,从⽽也就没有必要对该变量进⾏同步了。
ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的变量封装进ThreadLocal。
14、Spring的⾃动装配有哪些:
在spring中,对象⽆需⾃⼰查或创建与其关联的其他对象,由容器负责把需要相互协作的对象引⽤赋予各个对象,使⽤autowire来配置⾃动装载模式。
在Spring框架中使⽤注解的装配⽅式:
使⽤@Autowired注解来⾃动装配指定的bean。在使⽤@Autowired注解之前需要在Spring配置⽂件进⾏配置:
<context:annotation-config />。
在启动spring IoC时,容器⾃动装载了⼀个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、
@Resource或@Inject时,就会在IoC容器⾃动查需要的bean,并装配给该对象的属性。
在使⽤@Autowired时,⾸先在容器中查询对应类型的bean:
(1)如果查询结果刚好为⼀个,就将该bean装配给@Autowired指定的数据;
(2)如果查询的结果不⽌⼀个,那么@Autowired会根据名称来查;
(3)如果上述查的结果为空,那么会抛出异常。解决⽅法时,使⽤required=false。
@Autowired可⽤于:构造函数、成员变量、Setter⽅法
注:@Autowired和@Resource之间的区别
(1) @Autowired默认是按照类型装配注⼊的,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。
(2) @Resource默认是按照名称来装配注⼊的,只有当不到与名称匹配的bean才会按照类型来装配注⼊。
⾃动装配类型:
(1)autowire byName (按名称⾃动装配)
①将查其类中所有的set⽅法名,例如setCat,获得将set去掉并且⾸字母⼩写的字符串,即cat。
②去spring容器中寻是否有此字符串名称id的对象。
如果有,就取出注⼊;如果没有,就报空指针异常。
(2)autowire byType (按类型⾃动装配)
使⽤autowire byType⾸先需要保证:同⼀类型的对象,在spring容器中唯⼀。如果不唯⼀,会报不唯
⼀的异常。
(3)⾃动装配autowire
⾸先尝试使⽤constructor进⾏⾃动装配,如果失败,再尝试使⽤byType进⾏⾃动装配
(4)constructor
把与Bean的构造器⼊参具有相同类型的其他Bean⾃动装配到Bean构造器的对应⼊参中。
15、Spring 框架中都⽤到了哪些设计模式?
(1)⼯⼚模式:BeanFactory就是简单⼯⼚模式的体现,⽤来创建对象的实例;
(2)单例模式:Bean默认为单例模式。
(3)代理模式:Spring的AOP功能⽤到了JDK的动态代理和CGLIB字节码⽣成技术;
(4)模板⽅法:⽤来解决代码重复的问题。⽐如. RestTemplate, JmsTemplate, JpaTemplate。
(5)观察者模式:定义对象键⼀种⼀对多的依赖关系,当⼀个对象的状态发⽣改变时,所有依赖于它的对象都会得到通知被制动更新,如Spring中listener的实现–ApplicationListener。
17、spring的事务传播⾏为:
spring事务的传播⾏为说的是,当多个事务同时存在的时候,spring如何处理这些事务的⾏为。
(1)PROPAGATION_REQUIRED:如果当前没有事务,就创建⼀个新事务,如果当前存在事务,就加⼊该事务,该设置是最常⽤的设置。
(2)PROPAGATION_SUPPORTS:⽀持当前事务,如果当前存在事务,就加⼊该事务,如果当前不存在事务,就以⾮事务执⾏。‘(3) PROPAGATION_MANDATORY:⽀持当前事务,如果当前存在事务,就加⼊该事务,如果当前不存在事务,就抛出异常。
(4) PROPAGATION_REQUIRES_NEW:创建新事务,⽆论当前存不存在事务,都创建新事务。
(5) PROPAGATION_NOT_SUPPORTED:以⾮事务⽅式执⾏操作,如果当前存在事务,就把当前事务挂起。
(6) PROPAGATION_NEVER:以⾮事务⽅式执⾏,如果当前存在事务,则抛出异常。
(7) PROPAGATION_NESTED:如果当前存在事务,则在嵌套事务内执⾏。如果当前没有事务,则按REQUIRED属性执⾏。
我的总结:
(1)REQUIRED代表如果已经存在⼀个事务,就加⼊到这个事务中。如果当前没有事务,就新建⼀个事务,这是默认的事务传播设置。⽩话解释:如果马路上有车就搭车,如果马路上没有车就造⼀个车。
(2)SUPPORTS代表如果已经存在⼀个事务,就加⼊到这个事务中。如果当前没有事务,就以⾮事务⽅式执⾏。
⽩话解释:如果马路上有车就搭车,如果马路上没有车就⾃⼰⾛绿⾊环保。
(3)MANDATORY代表如果已经存在⼀个事务,就加⼊到这个事务中。如果当前没有事务,就抛出异常。
⽩话解释:如果马路上有车就搭车,如果马路上没有车就愤怒的爆炸。
(4)REQUIRES_NEW代表新建事务,如果已经存在⼀个事务,就把这个事务挂起并创建新的事务。
⽩话解释:如果马路上有车也不搭车,还要⾃⼰造车。
(5)NOT_SUPPORTED代表如果已经存在⼀个事务,就把这个事务挂起。并以⾮事务⽅式执⾏操作。
⽩话解释:如果马路上有车也不搭车,⾃⼰⾛绿⾊环保。
(6)NEVER代表如果已经存在⼀个事务,则抛出异常。如果当前没有事务,以⾮事务⽅式执⾏。
⽩话解释:马路上有车就愤怒的爆炸,⼀台车都没有时则⾃⼰⾛绿⾊环保。
(7)NESTED代表创建当前事务的⼦事务。
⽩话解释:⽔和鱼的关系,鱼(⼦事务)没有了但不影响⽔(⽗事务),但⽔(⽗事务)没有了则影响鱼(⼦事务)。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。