Spring是如何简化开发的?
- 基于POJO(bean对象)的轻量级和最小侵入性编程(不会影响自己的业务逻辑和功能)。
- 通过依赖注入和面向接口实现松耦合(如实现spring提供的接口并扩展功能)。
- 基于切面和惯例进行声明式编程(如声明式事物)。
- 通过切面和模板减少样板代码(切面实现统一功能,如统计方法的运行时间等)。
说说你对spring的理解
spring是一个框架,是一个容器,也是一个生态(spring全家桶的基础),是整个spring生态的基石。
spring的核心
spring是一个IOC和AOP1容器框架。
- IOC:控制反转(由容器来实现对象管理和属性的注入等功能)。
- AOP:面向切面编程
- 容器:包含并管应用对象的生命周期。
spring的事务传播机制
多个事务方法相互调用时,事务如何在这些方法之间进行传播spring中提供了7中不同的传播特性,来保证事务的正常执行:
- REQUIRED:默认的传播特性,如果当前没有事务,则新建一个事务,如果当前存在事务,则加入这个事务
- SUPPORTS:当前存在事务,则加入当前事务,如果当前没有事务,则以非事务的方式执行
- MANDATORY:当前存在事务,则加入当前事务,如果当前事务不存在,则抛出异常
- REOUIRED NEW:创建一个新事务,如果存在当前事务,则挂起该当前存在的事务
- NOT SUPPORTED:以非事务方式执行,如果存在当前事务,则挂起当前事务
- NEVER:不使用事务,如果当前事务存在,则抛出异常
- NESTED:如果当前事务存在,则在嵌套事务中执行,否则REOUIRED的操作一样
- NESTED和REOUIRED NEW的区别:
REQUIRED NEW是新建一个事务并且新开始的这个事务与原有事务无关,而NESTED则是当前存在事务时会开启一个嵌套事务,在NESTED情况下,父事务回滚时,子事务也会回滚,而REQUIRED NEW情况下,原有事务回滚,不会影响新开启的事务 - NESTED和REOUIRED的区别:
REQUIRED情况下,调用方存在事务时,则被调用方和调用方使用同一个事务,那么被调用方出现异常时,由于共用一个事务,所以无论是否catch异常,事务都会回滚,而在NESTED情况下,被调用方发生异常时,调用方可以catch其异常,这样只有子事务回滚,父事务不会回滚。
spring框架中的单例bean 是线程安全的么?
Spring中的Bean对象默认是单例的,框架并没有对bean进行多线程的封装处理。
如果Bean是有状态的(有状态就是由数据存储的功能,无状态就是不会存储数据,),那么就需要开发人员自己来保证线程安全的保证,最简单的办法就是改变bean的作用域把singleton改成prototype,这样每次请求bean对象就相当于是创建新的对象来保证线程的安全。
想一下,我们的controller,service和dao本身并不是线程安全的,只是调用里面的方法,而且多线程调用一个实例的方法,会在内存中复制遍历,这是自己线程的工作内存,是最安全的。
因此在进行使用的时候,不要在bean中声明任何有状态的实例变量或者类变量,如果必须如此,也推荐大家使用ThreadLocal把变量变成线程私有,如果bean的实例变量或者类变量需要在多个线程之间共享,那么就只能使用synchronized,lock,cas等这些实现线程同步的方法了。
spring框架中使用了哪些设计模式及应用场景
1.工厂模式,在各种BeanFactory以及ApplicationContext创建中都用到了
2.模版模式,在各种BeanFactory以及ApplicationContext实现中也都用到了
3.代理模式,SpringAOP 利用了AspectJAOP实现的!AspectJAOP的底层用了动态代理
4.策略模式,加载资源文件的方式,使用了不同的方法,比如:ClassPathResourece,
FileSystemResource,ServletContextResource,UrlResource但他们都有共同的借口Resource;在Aop的实现中,采用了两种不同的方式,JDK动态代理和CGLIB代理
5.单例模式,比如在创建bean的时候。
6.观察者模式,spring中的ApplicationEvent,ApplicationListener,ApplicationEventPublisher
7.适配器模式,MethodBeforeAdviceAdapterThrowsAdviceAdapterAfterReturningAdapter
8.装饰者模式,源码中类型带Wrapper或者Decorator的都是
spring事务的隔离级别
spring中的事务的隔离级别和mysql中的事务隔离级别是一样的,在进行配置的时候,如果数据库和spring代码中的隔离级别不同,那么以spring的配置为主。
spring中事务的实现原理
在使用Spring框架的时候,可以有两种事务的实现方式,一种是编程式事务,有用户自己通过代码来控制事务的处理逻辑,还有一种是声明式事务,通过@Transactional注解来实现。
其实事务的操作本来应该是由数据库来进行控制,但是为了方便用户进行业务逻辑的操作,spring对事务功能进行了扩展实现,一般我们很少会用编程式事务,更多的是通过添加@Transactional注解来进行实现,当添加此注解之后事务的自动功能就会关闭,有spring框架来帮助进行控制。
其实事务操作是AOP的一个核心体现,当一个方法添加@Transactional注解之后,spring会基于这个类生成一个代理对象,会将这个代理对象作为bean,当使用这个代理对象的方法的时候,如果有事务处理,那么会先把事务的自动提交给关闭,然后去执行具体的业务逻辑,如果执行逻辑没有出现异常,那么代理逻辑就会直接提交如果出现任何异常情况,那么直接进行回滚操作,当然用户可以控制对哪些异常进行回滚操作。
spring事务什么时候会失效
- bean对象没有被spring容器管理。
- 方法的访问修饰符不是public
- 自身调用问题
- 数据源没有配置事务管理器
- 数据库不支持事务
- 异常被捕获
- 异常类型错误或者配置错误。
spring支持的bean的作用域有哪些?
- singleton
使用该属性定义Bean时,IOC容器仅创建一个Bean实例,IOC容器每次返回的是同一个Bean实例。 - prototype
使用该属性定义Bean时,IOC容器可以创建多个Bean实例,每次返回的都是一个新的实例。 - request
该属性仅对HTTP请求产生作用,使用该属性定义Bean时,每次HTTP请求都会创建一个新的Bean,适用于 WebApplicationContext环境。 - session
该属性仅用于HTTP Session,同一个Session共享一个Bean实例。不同Session使用不同的实例。 - global-session
该属性仅用于HTTP Session,同session作用域不同的是,所有的Session共享一个Bean实例。
简述spring bean的生命周期
1、实例化bean对象
通过反射的方式进行对象的创建,此时的创建只是在堆空间中申请空间,属性都是默认值
2、设置对象属性
给对象中的属性进行值的设置工作
3、检查Aware相关接口并设置相关依赖
如果对象中需要引用容器内部的对象,那么需要调用aware接口的子类方法来进行统一的设置
4、BeanPostProcessor的前置处理
对生成的bean对象进行前置的处理工作
5、检查是否是InitializingBean的子类来决定是否调用afterPropertiesSet方法
判断当前bean对象是否设置了InitializingBean接口,然后进行属性的设置等基本工作
6、检查是否配置有自定义的init-method方法
如果当前bean对象定义了初始化方法,那么在此处调用初始化方法
7、BeanPostProcessor后置处理
对生成的bean对象进行后置的处理工作
8、注册必要的Destruction相关回调接口
为了方便对象的销毁,在此处调用注销的回调接口,方便对象进行销毁操作
如何实现一个IOC容器
lOC(lnversion ofControl),意思是控制反转,不是什么技术,而是一种设计思想,IOC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。
在传统的程序设计中,我们直接在对象内部通过new进行对象创建,是程序主动去创建依赖对象,而IOC是有专门的容器来进行对象的创建,即IOC容器来控制对象的创建。
在传统的应用程序中,我们是在对象中主动控制去直接获取依赖对象,这个是正转,反转是由容器来帮忙创建及注入依赖对象,在这个过程过程中,由容器帮我们查找级注入依赖对象,对象只是被动的接受依赖对象。
1、先准备一个基本的容器对象,包含一些map结构的集合,用来方便后续过程中存储具体的对象
2、进行配置文件的读取工作或者注解的解析工作,将需要创建的bean对象都封装成BeanDefinition对象存储在容器中
3、容器将封装好的BeanDefinition对象通过反射的方式进行实例化,完成对象的实例化工作
4、进行对象的初始化操作,也就是给类中的对应属性值就行设置,也就是进行依赖注入,完成整个对象的创建,变成一个完整的bean对象,存储在容器的某个map结构中
5、通过容器对象来获取对象,进行对象的获取和逻辑处理工作
6、提供销毁操作,当对象不用或者容器关闭的时候,将无用的对象进行销毁
什么是嵌入式服务器?为什么使用嵌入式服务器?
在springboot框架中,大家应该发现了有一个内嵌的tomcat,在之前的开发流程中,每次写好代码之后必须要将项目部署到一个额外的web服务器中,只有这样才可以运行,这这个明显要麻烦很多,而使用springboot的时候,你会发现在启动项目的时候可以直接按照java应用程序的方式来启动项目,不需要额外的环境支持,也不需要 tomcat服务器,这是因为在springboot框架中内置了tomcatjar,来来通过main方法启动容器,达到一键开发部署的方式,不需要额外的任何其他操作。
说一下使用spring的优势?
1、Spring通过DI、AOP和消除样板式代码来简化企业级Java开发
2、Spring框架之外还存在一个构建在核心框架之上的庞大生态圈,它将Spring扩展到不同的领域,如Web服务、REST、移动开发以及NoSQL
3、低侵入式设计,代码的污染极低
4、独立于各种应用服务器,基于Spring框架的应用,可以真正实现Write OnceRun Anywhere的承诺
5、Spring的loC容器降低了业务对象替换的复杂性,提高了组件之间的解耦
6、Spring的AOP支持允许将一些通用任务如安全、事务、日志等进行集中式处理,从而提供了更好的复用
7、Spring的ORM和DAO提供了与第三方持久层框架的的良好整合,并简化了底层的数据库访问
8、Spring的高度开放性,并不强制应用完全依赖于Spring,开发者可自由选用Spring框架的部分或全部
说说你对AOP的理解?
- AOP全称叫做AspectOrientedProgramming面向切面编程。它是为解耦而生的,解耦是程序员编码开发过程中一直追求的境界,AOP在业务类的隔离上,绝对是做到了解耦,在这里面有几个核心的概念
- 切面(Aspect):指关注点模块化,这个关注点可能会横切多个对象。事务管理是企业级lava应用中有关横切
- 关注点的例子。在SpringAOP中,切面可以使用通用类基于模式的方式(schema-basedapproach)或者在普通类中以@Aspect注解(@Aspect注解方式)来实现。
- 连接点(joinpoint):在程序执行过程中某个特定的点,例如某个方法调用的时间点或者处理异常的时间点在SpringAOP中,一个连接点总是代表一个方法的执击。
- 通知(Advice):在切面的某个特定的连接点上执行的动作。通知有多种类型,包括“around”“before"and“after”等等。通知的类型将在后面的章节进行讨论。许多AOP框架,包括Spring在内,都是以拦截器做通知模型的,并维护着一个以连接点为中心的拦截器链。
- 切点(Pointcut):匹配连接点的断言。通知和切点表达式相关联,并在满足这个切点的连接点上运行(例如,当执行某个特定名称的方法时)。切点表达式如何和连接点匹配是AOP的核心:Spring默认使用Aspect切点语义。
- 引入(Introduction):声明额外的方法或者某个类型的字段。Spring允许引入新的接口(以及一个对应的实现)到任何被通知的对象上。例如,可以使用引入来使bean实现IsModified接口,以便简化缓存机制(在 Aspecti社区,引入也被称为内部类型声明(inter))。
- 目标对象(Targetobject):被一个或者多个切面所通知的对象。也被称作被通知(advised)对象。既然 SpringAOP是通过运行时代理实现的,那么这个对象永远是一个被代理(proxied)的对象。
- AOP代理(AOPproxv):AOP框架创建的对象,用来实现切面契约(aspectcontract)(包括通知方法执行等功能)。在Spring中,AOP代理可以是JDK动态代理或CGLIB代理。
- 织入(Weaving):把切面连接到其它的应用程序类型或者对象上,并创建一个被被通知的对象的过程。这个过程可以在编译时(例如使用Aspectj编译器)、类加载时或运行时中完成。Spring和其他纯JavaAOP框架一样,是在运行时完成织入的。
这些概念都太学术了,如果更简单的解释呢,其实非常简单:
任何一个系统都是由不同的组件组成的,每个组件负责一块特定的功能,当然会存在很多组件是跟业务无关的,例如日志,事务、权限等核心服务组件,这些核心服务组件经常融入到具体的业务逻辑中,如果我们为每一个具体业务逻辑操作都添加这样的代码,很明显代码冗余太多,因此我们需要将这些公共的代码逻辑抽象出来变成一个切面,然后注入到目标对象(具体业务)中去,AOP正是基于这样的一个思路实现的,通过动态代理的方式,将需要注入切面的对象进行代理,在进行调用的时候,将公共的逻辑直接添加进去,而不需要修改原有业务的逻辑代码,只需要在原来的业务逻辑基础之上做一些增强功能即可。
谈谈你对IOC容器的理解
如果这个过程比较难理解的话,那么可以想象自己找女朋友和婚介公司找女朋友的过程。如果这个过程能够想明白的话,那么我们现在回答上面的问题:
1、谁控制谁:在之前的编码过程中,都是需要什么对象自己去创建什么对象,
有程序员自己来控制对象,而有了IOC容器
之后,就会变成由IOC容器来控制对象,工
2、控制什么:在实现过程中所需要的对象及需要依赖的对象
3、什么是反转:在没有IOC容器之前我们都是在对象中主动去创建依赖的对象,这是正转的,而有了IOc之后,依赖的对象直接由IOC容器创建后注入到对象中,由主动创建变成了被动接受,这是反转
4、哪些方面被反转:依赖的对象
beanFactory和FactoryBean的区别?