2021-12-02

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实现。

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 是被代理目标实例某个方法的具体入参, 在方法反射调用时使用。

使用如下代码创建代理类:

Proxy.newProxyInstance(Test1.class.getClassLoader(),

dangdangBook.getClass().getInterfaces(), handler);

5、介绍一下静态和动态代理以及区别?

AOP技术的原理是“代理模式”,AOP代理主要分为静态代理和动态代理。

(A)普通的类和接口实现静态代理,代理类绑死了接口。

另外也可以使用AspectJ是静态代理的增强,所谓静态代理,就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强,他会在编译阶段将AspectJ(切面)织入到Java字节码中,运行的时候就是增强之后的AOP对象。

参考网址:

Java 静态代理 AspectJ 使用

https://www.jianshu.com/p/aa293edba2e4

Spring AOP,AspectJ, CGLIB 有点晕

https://www.jianshu.com/p/fe8d1e8bd63e

(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意味着将你设计好的对象交给容器控制,而不是传统的在对象内部直接控制。理解“谁控制谁,控制什么,为何是反转(有反转是不是有正转),反转了哪些”

1

 谁控制谁,控制什么:传统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

(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,在web.xml中进行配置,代码如下:

org.springframework.web.context.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) {

PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);

}

1

2

3

BeanFactory:

是spring里面最底层的接口,提供了最简单的容器的功能,只提供实例化对象和获取对象

applicationContext:

应用上下文,继承了BeanFactory接口(上一个的子接口),提供了更多的功能

1.ClassPathXmlApplicationContext 从 classpath 加载 spring 的配置文件

2.FileSystemApplicationContext 从系统文件加载 spring 的配置文件

3.AnnotationConfigApplicationContext 获取基于注解的 spring 容器对象

4.XmlWebApplicationContext 在web环境中获取 spring 容器对象

9、请解释Spring Bean的生命周期?

首先说一下Servlet的生命周期:实例化,初始init,接收请求service,销毁destroy;

Spring上下文中的Bean生命周期也类似,如下:

(1)实例化Bean:

对于BeanFactory容器,当客户向容器请求一个尚未初始化的bean时,或初始化bean的时候需要注入另一个尚未初始化的依赖时,容器就会调用createBean进行实例化。对于ApplicationContext容器,当容器启动结束后,通过获取BeanDefinition对象中的信息,实例化所有的bean。

(2)设置对象属性(依赖注入):

实例化后的对象被封装在BeanWrapper对象中,紧接着,Spring根据BeanDefinition中的信息 以及 通过BeanWrapper提供的设置属性的接口完成依赖注入。

(3)处理Aware接口:

接着,Spring会检测该对象是否实现了xxxAware接口,并将相关的xxxAware实例注入给Bean:

①如果这个Bean已经实现了BeanNameAware接口,会调用它实现的setBeanName(String beanId)方法,此处传递的就是Spring配置文件中Bean的id值;

②如果这个Bean已经实现了BeanFactoryAware接口,会调用它实现的setBeanFactory()方法,传递的是Spring工厂自身。

③如果这个Bean已经实现了ApplicationContextAware接口,会调用setApplicationContext(ApplicationContext)方法,传入Spring上下文;

(4)BeanPostProcessor:

如果想对Bean进行一些自定义的处理,那么可以让Bean实现了BeanPostProcessor接口,那将会调用postProcessBeforeInitialization(Object obj, String s)方法。

(5)InitializingBean 与 init-method:

如果Bean在Spring配置文件中配置了 init-method 属性,则会自动调用其配置的初始化方法。

(6)如果这个Bean实现了BeanPostProcessor接口,将会调用postProcessAfterInitialization(Object obj, String s)方法;由于这个方法是在Bean初始化结束时调用的,所以可以被应用于内存或缓存技术;

以上几个步骤完成后,Bean就已经被正确创建了,之后就可以使用这个Bean了。

(7)DisposableBean:

当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接口,会调用其实现的destroy()方法;

(8)destroy-method:

最后,如果这个Bean的Spring配置中配置了destroy-method属性,会自动调用其配置的销毁方法。

还可以参考网址:https://www.cnblogs.com/kenshinobiy/p/4652008.html

10、解释Spring支持的几种bean的作用域。

Spring容器中的bean可以分为5个范围:

(1)singleton:默认,每个容器中只有一个bean的实例,单例的模式由BeanFactory自身来维护。

(2)prototype:为每一个获得bean的请求创建一个新的实例。

(3)request:为每一个网络请求创建一个实例,在请求完成以后,bean会失效并被垃圾回收器回收。

(4)session:与request范围类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。

(5)global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。

其中比较常用的是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。

13、Spring基于xml注入bean的几种方式:

(1)Set方法注入;

(2)构造器注入:①通过index设置参数的位置;②通过type设置参数类型;

(3)静态工厂注入;

(4)实例工厂;

详细内容可以阅读:https://blog.csdn.net/a745233700/article/details/89307518

14、Spring的自动装配有哪些:

在spring中,对象无需自己查找或创建与其关联的其他对象,由容器负责把需要相互协作的对象引用赋予各个对象,使用autowire来配置自动装载模式。

在Spring框架xml配置中共有5种装配方式:

(1)no:默认的方式是不进行自动装配的,需要通过手工设置ref属性来进行装配bean。

(2)byName:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。

(3)byType:通过参数的数据类型进行自动装配。使用@autowire。

(4)constructor:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。

(5)autodetect:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。参考:https://www.yiibai.com/spring/spring-autowiring-by-autodetect.html

在Spring框架中使用注解的装配方式:

使用@Autowired注解来自动装配指定的bean。在使用@Autowired注解之前需要在Spring配置文件进行配置:

在启动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。

16、Spring事务处理有哪两种方式:

Spring事务的本质其实就是数据库对事务的支持,只不过Spring框架进行了封装,如果没有底层数据库对事务的支持,spring是无法提供事务功能的。

Spring支持编程式事务管理和声明式事务管理两种方式:

(1)编程式事务管理使用TransactionTemplate类,使用较少。

(2)声明式事务管理建立在AOP之上的,使用较多。该方式本质是通过AOP功能对方法前后进行拦截,将事务处理的功能编织到拦截的方法中,也就是在目标方法开始之前加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。

声明式事务最大的优点就是不需要在业务逻辑代码中掺杂事务管理的相关代码,只需在配置文件中做相关的事务规则声明或通过@Transactional注解的方式,便可以将事务规则应用到业务逻辑中。

声明式事务管理要优于编程式事务管理,这正是spring倡导的非侵入式的开发方式,使业务代码不受污染,只要加上注解就可以获得完全的事务支持。唯一不足地方是,最细粒度只能作用到方法级别,无法做到像编程式事务那样可以作用到代码块级别。

透彻的掌握 Spring 中@transactional 的使用

https://www.ibm.com/developerworks/cn/java/j-master-spring-transactional-use/index.html

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代表创建当前事务的子事务。

白话解释:水和鱼的关系,鱼(子事务)没有了但不影响水(父事务),但水(父事务)没有了则影响鱼(子事务)。

18、Spring中的隔离级别:

(1) ISOLATION_DEFAULT:这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。

(2) ISOLATION_READ_UNCOMMITTED:读未提交,允许另外一个事务可以看到这个事务未提交的数据。

(3) ISOLATION_READ_COMMITTED:读已提交,保证一个事务修改的数据提交后才能被另一事务读取,而且能看到该事务对已有记录的更新。

(4) ISOLATION_REPEATABLE_READ:可重复读,保证一个事务修改的数据提交后才能被另一事务读取,但是不能看到该事务对已有记录的更新。

(5) ISOLATION_SERIALIZABLE:一个事务在执行的过程中完全看不到其他事务对数据库所做的更新。

19、Spring框架中有哪些不同类型的事件?

Spring 提供了以下5种标准的事件:

(1)上下文更新事件(ContextRefreshedEvent):在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。

(2)上下文开始事件(ContextStartedEvent):当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。

(3)上下文停止事件(ContextStoppedEvent):当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。

(4)上下文关闭事件(ContextClosedEvent):当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。

(5)请求处理事件(RequestHandledEvent):在Web应用中,当一个http请求(request)结束触发该事件。

如果一个bean实现了ApplicationListener接口,当一个ApplicationEvent 被发布以后,bean会自动被通知。

20、解释一下Spring AOP里面的几个名词:

(1)切面(Aspect):被抽取的公共模块,可能会横切多个对象。 在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以 @AspectJ 注解来实现。

(2)连接点(Join point):指方法,在Spring AOP中,一个连接点 总是 代表一个方法的执行。

(3)通知(Advice):在切面的某个特定的连接点(Join point)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。

(4)切入点(Pointcut):切入点是指 我们要对哪些Join point进行拦截的定义。通过切入点表达式,指定拦截的方法,比如指定拦截add*、search*。

(5)引入(Introduction):(也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。

参考URL:https://blog.csdn.net/Danny_idea/article/details/78232298

(6)目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做 被通知(adviced) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。

(7)织入(Weaving):指把增强应用到目标对象来创建新的代理对象的过程。Spring是在运行时完成织入。

切入点(pointcut)和连接点(join point)匹配的概念是AOP的关键,这使得AOP不同于其它仅仅提供拦截功能的旧技术。 切入点使得定位通知(advice)可独立于OO层次。 例如,一个提供声明式事务管理的around通知可以被应用到一组横跨多个对象中的方法上(例如服务层的所有业务操作)。

21、Spring通知有哪些类型?

参考:https://blog.csdn.net/qq_32331073/article/details/80596084

(1)前置通知(Before advice):在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。

(2)返回后通知(After returning advice):在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。

(3)抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知。

(4)最终通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回的还是异常退出的)。

(5)环绕通知(Around Advice):包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。 环绕通知是最常用的一种通知类型。大部分基于拦截的AOP框架,例如Nanning和JBoss4,都只提供环绕通知。

使用注解法实现通知时,使用同一个aspect,但使用不同的advice的执行顺序:

(1)没有异常情况下的执行顺序:

around before advice

before advice

target method 执行

around after advice

after advice

afterReturning

(2)有异常情况下的执行顺序:

around before advice

before advice

target method 执行

around after advice

after advice

afterThrowing:异常发生

java.lang.RuntimeException: 异常发生

22、介绍一下Spring有哪些模块及其作用?

1、Spring core 是spring框架的核心,提供了IOC和依赖注入特性。

2、Spring Context 提供了一种框架风格的方式来访问对象,继承了beans包的功能,同时增加了国际化、事件传播、资源装载、以及透明创建上下文。

3、Spring AOP 通过配置管理,直接将面向切面编程技术集成到了框架之中。

4、Spring DAO 提供了JDBC的抽象层。可以消除冗长的JDBC编码和数据库厂商特有的错误代码。

5、Spring ORM Spring框架插入了若干个ORM框架,从而提供了ORM对象关系工具,其中包括JDO、Hibernate、Ibatis、Mybatis等,所有这些都遵从Spring的事务和DAO异常层次结构。

6、Spring Web 此模块建立在应用程序上下文模块程序之上,为web应用程序提供了上下文,所以他支持与Struts1或Struts2或SpringMVC的集成。

7、SpringMVC是一个全功能的构建web应用程序的mvc实现。

8、Spring ORM是对象与表关系映射,通过对象直接操作表。

23、自动扫描包

在一个稍大的项目中,通常会有上百个组件,如果这些组件采用XML的bean定义来配置,显然会增加配置文件的体积,查找及维护起来也不太方便。

Spring2.5为我们引入了组件自动扫描机制,使用注解 后可以在类路径底下寻找标注了@Component、@Service、@Controller、@Repository注解的类,并把这些类纳入进Spring容器中管理,它的作用和在XML文件中使用bean节点配置组件是一样的。

24、常见Spring注解的解释

@Controller:只能用控制器类上

@Service:只能用在业务类上

@Repository:只能用在dao类上

@Component:工具类的组件使用此注解

@Bean:在方法上面使用@Bean注解代表声明一个创建bean的工厂方法,并且交给Spring容器管理;当使用此Bean时直接使用@Autowire进行注入即可。

@Aspect:表明整个类是一个切面。

@Component:标记该类是一个组件,spring扫描注解配置时,会标记这些类要生成bean

@Pointcut:注解声明对应的方法为切入点。

@Inject:和@Autowired注解一样,@Inject可以用来自动装配属性、方法和构造器;与@Autowired不同的是,@Inject没有required属性。因此@Inject注解所标注的依赖关系必须存在,如果不存在,则会抛出异常。

@Named:相对于@Autowired对应的Qualifier,@Inject所对应的是@Named注解。

25、注解的分类

注解分为两类:

1、一类是使用Bean,即是把已经在xml文件中配置好的Bean拿来用,完成属性、方法的组装;比如@Autowired , @Resource,可以通过byTYPE(@Autowired)、byNAME(@Resource)的方式获取Bean;

2、一类是注册Bean,@Component , @Repository , @ Controller , @Service , @Configration这些注解都是把你要实例化的对象转化成一个Bean,放在IoC容器中,等你要用的时候,它会和上面的@Autowired , @Resource配合到一起,把对象、属性、方法完美组装。

26、谈谈你对spring的理解

从spring的工作原理、核心技术、优缺点

spring的工作原理:

spring是按照设计模式精细打造的,它实现了工厂模式的工厂类,这个类名为BeanFactory(接口),常常使用它的子接口ApplicationContext

spring的核心是IOC(控制反转),IOC是一种设计思想,用于实现模块之间的解耦,在Spring中它的作用是对对象的创建,维护和销毁生命周期的控制。IOC:把对象的创建、初始化、销毁、交给Spring来管理,而不是由开发者,实现了控制反转

spring是一个大的工厂类,spring的特点就是基于配置,在其配置文件中通过来创建实例对象

根据业务逻辑来看,对象经常不是独立的,一个对象的创建往往涉及到另一个对象的

创建,当然这个对象也要由IOC容器负责,负责的方式就是依赖注入DI,通过反射机制实现。有三种注入方式:(1)接口注入、(2)构造器注入、(3)setter方法注入。

另外一个工作原理AOP请参考前面的答案。

Spring的核心技术

Spring的核心技术:IOC、AOP

Java的高级特性:反射机制,代理

AOP:面向切面编程,系统中有很多各不相干的类的方法,在这众多方法中加入某种系统功能的代码,如加入日志、权限、判断等,AOP可以实现横切关注点(如日志,安全,缓存和事务管理)与他们所影响的对象之间的解耦。

实现AOP功能采用的是代理技术,调用代理类,代理类与目标类具有相同的方法声明。

AOP在spring中主要表现在两个方面:提供声明式的事务管理、spring支持用户自定义切面

AOP主要包括通知(advice)切点(point cut)连接点(join point)

Spring的优缺点

Spring的核心概念是IOC和AOP,这两个核心服务的对象是bean,定位是一个轻量级的框架。

优点:

Spring中避免了关键字new造成的耦合问题

Spring本身就是一个工厂,不需要再编写工厂类

Spring不需要进行明确的引用关系的传递,直接通过配置完成

所有框架几乎都可以在spring中整合使用

Spring编程=factory设计模式+proxy设计模式

缺点:

应用代码与Spring的API发生了紧耦合。Spring模块众多,学习成本高。Spring的内容太庞大,随便打断点查﹁看的时候会出现十几二十层代码,代码非常复杂,阅览性不强,在实际开发的过程中spring的角色更像是胶水一样,将不同的框架粘合整合起来,充当整合粘合各种技术的角色,同时作为bean的容器。

27、延迟和立即加载的优点

延迟实例化的优点(BeanFactory)

应用启动的时候占用资源很少;对资源要求较高的应有,比较有优势

立即实例化的优点(ApplicationContext)

1.所有的Bean在启动的时候都加载,系统运行的速度快

2.在启动的时候所有Bean都加载,就能在系统启动的时候尽早的发现系统中的配置问题

3.建议web应用中,在启动的时候就把所有的Bean都加载了(把费时操作放到系统启动中完成)

28、Spring框架中,工厂模式,单例模式,代理模式在哪里有应用

(1)工厂模式:BeanFactory用来创建对象的实例。

通常由应用程序直接使用new创建新的对象,为了将对象的创建和使用相分离,采用工厂模式,即应用程序将对象的创建及初始化职责交给工厂对象。一般情况下,应用程序有自己的工厂对象来创建bean.如果将应用程序自己的工厂对象交给Spring管理,那么Spring管理的就不是普通的bean,而是工厂Bean。

(2)单例模式:在spring配置文件中定义的bean默认为单例模式。

1.饿汉模式

将构造方法设为私有,并设置成员变量并初始化对象(立即加载)。通过静态方法返回初始化对象

2.懒汉模式

将构造方法设为私有,设置成员变量并不初始化(延迟加载),通过静态方法返回new出的对象,首先判断成员变量是否为空,然后为new出对象的代码加上锁,最后再判断一次成员变量是否为空,最后new出对象

3.静态内部类实现

静态内部类虽然保证了单例在多线程并发下的线程安全,但是在遇到序列化对象时,默认的方式运行得到的结果就是多例的

4.static静态代码块实现

5.内部枚举类实现

(3)代理模式:在AOP和remoting中被用的比较多。

静态代理和动态代理本质区别:是否需要修改源代码(不包含测试类),就可以控制代理内容的变化。

A. 静态代理:程序写好之后,想修改代理过程,就必须修改源代码。

优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。

缺点:需要为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。

B. 动态代理:程序写好后,更改代理过程。只需要修改代理对象(分身)

JDK动态代理:代理类实现invocationHandler

优点:相对于静态代理,动态代理大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度。

缺点:需要被代理类实现接口。

CGLIB动态代理:CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承,所以不能对final修饰的类进行代理。

优点:CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,对于单例的对象,因为无需频繁创建对象,用CGLIB合适。

缺点:CGLIB创建代理对象时所花费的时间却比JDK多得多。

JDK动态代理是需要根据接口创建出新的实现类,新的实现类是目标类的代理类。而CGLIB是根据父类创建出新的子类,新的子类就是父类的代理类,

29、Spring通知有哪五种常见类型?

1.前置通知:

在目标方法执行之前执行通知

前置通知方法,可以没有参数,也可以额外接收一个JoinPoint,Spring会自动将该对象传入,代表当前的连接点,通过该对象可以获取目标对象和目标方法相关的信息。

注意,如果接收JoinPoint,必须保证其为方法的第一个参数,否则报错。

2.环绕通知:

在目标方法执行之前和之后都可以执行额外代码的通知

在环绕通知中必须显式的调用目标方法,目标方法才会执行,这个显式调用时通过ProceedingJoinPoint来实现的,可以在环绕通知中接收一个此类型的形参,spring容器会自动将该对象传入,注意这个参数必须处在环绕通知的第一个形参位置。

注意:只有环绕通知可以接收ProceedingJoinPoint,而其他通知只能接收JoinPoint。

环绕通知需要返回返回值,否则真正调用者将拿不到返回值,只能得到一个null。

环绕通知有控制目标方法是否执行、有控制是否返回值、有改变返回值的能力。环绕通知虽然有这样的能力,但一定要慎用,不是技术上不可行,而是要小心不要破坏了软件分层的“高内聚 低耦合”的目标。

3.后置通知

在目标方法执行之后执行的通知。在后置通知中也可以选择性的接收一个JoinPoint来获取连接点的额外信息,但是这个参数必须处在参数列表的第一个。

在后置通知中,还可以通过returning属性配置:

获取返回值,一定要保证JoinPoint处在参数列表的第一位,否则抛异常

4.异常通知

在目标方法抛出异常时执行的通知,可以配置传入JoinPoint获取目标对象和目标方法相关信息,但必须处在参数列表第一位。另外,还可以配置throwing="e"参数,让异常通知可以接收到目标方法抛出的异常对象

5.最终通知

是在目标方法之后执行的通知。和后置通知不同之处在于,后置通知是在方法正常返回后执行的通知,如果方法没有正常返-例如抛出异常,则后置通知不会执行。而最终通知无论如何都会在目标方法调用过后执行,即使目标方法没有正常的执行完成,类似于finally代码块的效果。另外,后置通知可以通过配置得到返回值,而最终通知无法得到。最终通知也可以额外接收一个JoinPoint参数,来获取目标对象和目标方法相关信息,但一定要保证必须是第一个参数。

30、ApplicationContext接口常见的3个实现类分别是什么?

(1)FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。用在直接从硬盘上某一个位置加载XML配置文件。

(2)ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。用在在类路径中加载XML配置文件,适用于Java类型的项目。

(3)WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean。用在在WEB环境中加载XML配置文件,适用于web类型的项目。

31、介绍一下三种实现IOC的方式?

• (1)构造器依赖注入:构造器依赖注入通过容器执行一个类的构造器来实现的,该类有一系列参数,每个参数代表一个对其他类的依赖。

• (2)Setter方法注入:Setter方法注入是容器通过调用无参构造器或无参static工厂 方法实例化bean之后,调用该bean的setter方法,即实现了基于setter的依赖注入。

(3)注解注入:使用@autowire注解进行注入

32、IOC容器中的Bean可以来自于哪些方式?

(1)XML配置文件。

(2)基于注解。

(3)基于javaconfig。

33、谈一下@autowired 和@resource区别是什么?

1、共同点

两者都可以写在字段和setter方法上。两者如果都写在字段上,那么就不需要再写setter方法。

2、不同点

(1)@Autowired

@Autowired为Spring提供的注解,需要导入包org.springframework.beans.factory.annotation.Autowired;只按照byType注入。

@Autowired注解是按照类型(byType)装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null值,可以设置它的required属性为false。如果我们想使用按照名称(byName)来装配,可以结合@Qualifier注解一起使用。

(2)@Resource

@Resource默认按照ByName自动注入,由J2EE提供,需要导入包javax.annotation.Resource。@Resource有两个重要的属性:name和type,而Spring将@Resource注解的name属性解析为bean的名字,而type属性则解析为bean的类型。所以,如果使用name属性,则使用byName的自动注入策略,而使用type属性时则使用byType自动注入策略。如果既不制定name也不制定type属性,这时将通过反射机制使用byName自动注入策略。

34、介绍Spring中常见注解及解释?

@Component:是一个标识类是IOC容器的一个组件确保被扫描器识别,注入进来

@Repossitory:声明dao层

@Lazy(value=true) :延迟加载

@Configuration:起到配置定义的作用,细节就是@Bean创建了JavaBean的细节信息

@ComponentScan(basePackages=""):扫包,也可以进行类扫描

@Scope(scopeName=“singleton”):单例

@Scope(scopeName=“prototype”):多例

@Service:声明业务类

@Autowrite:反射注入,如果找不到符合的JavaBean对象时,控制台会出现NoSuchBeanDefinitionException

@Primary:当Spring不知道具体注入那个实现类对象,使用这个设置优先级

@Qualifier:给service主键设置一个别名,注入指定别名的主键,适用于1个接口多个实现类

@Resource官方:可以使用byName或byType形式进行注入

@ImportResource(value=“ac.xml”):在Java类中导入xml文件中的配置

35、Spring怎么配置事务(具体说出一些关键的xml 元素)

配置事务的方法有两种:

1)、基于XML的事务配置。

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

value="oracle.jdbc.driver.OracleDriver" />

value="jdbc:oracle:thin:@rj-t42:1521:elvis" />

class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

expression="execution(* com.yintong.service.helloService.*(..))" />

pointcut-ref="helloServiceOperation" />


2)、基于注解方式的事务配置。

@Transactional:直接在Java源代码中声明事务的做法让事务声明和将受其影响的代码距离更近了,而且一般来说不会有不恰当的耦合的风险,因为,使用事务性的代码几乎总是被部署在事务环境中。

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx"

xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

transaction-manager="txManager" />

36、在Spring中可以通过哪几种方式实现注入

可以在Spring中使用4种方式实现注入:

(1)get/set方法注入

(2)构造器注入

(3)静态工厂方法注入

(4)实例工厂方法注入

37、如何在Spring中解决循环依赖的问题?

https://www.jianshu.com/p/b65c57f4d45d

https://www.jianshu.com/p/4463b9b81249

https://www.jianshu.com/p/8bb67ca11831

https://www.cnblogs.com/chenpt/p/9896618.html

总结:不要使用有叁构造注入,使用set方法解决循环依赖。

38、配置文件ApplicationContext.xml可以改成其它名字吗?

缺省情况下,它会在WEB-INF/applicationContext.xml文件找Spring的配置。可以通过定义一个元素名字为”contextConfigLocation”来改变Spring配置文件的位置。示例如下:

org.springframework.web.context.ContextLoaderListener

contextConfigLocation

/WEB-INF/xyz.xml

39、自动装配有哪些局限性 ?

  (1)重写: 仍需用 和 配置来定义依赖,意味着总要重写自动装配。

  (2)基本数据类型:不能自动装配简单的属性,如基本数据类型,String字符串,和类。

  (3)模糊特性:自动装配不如显式装配精确,如果有可能,建议使用显式装配。

你可能感兴趣的:(2021-12-02)