面试题
github.com/Homiss/Java… //文章一般,很多重复内容
github.com/Snailclimb/… //里面有关于spring的内容
容器-BeanFactory和ApplicationContext的区别?
最基本的容器功能(注入数据/java项目)
BeanFactory
更多的容器功能(除了依赖注入,还有拦截器、WebApplicationContext/web项目(比如从xml加载定义配置文件或从类路径,最佳实践和最常用是从xml加载)等功能)
ApplicationContext //就是支持的功能更多一点而已,因为后者继承了前者
多了哪些功能?
BeanFactory和ApplicationContext是Spring中两种很重要的容器,前者提供了最基本的依赖注入的支持,后者在继承前者的基础上进行了功能的拓展,增加了事件传播,资源访问,国际化的支持等功能。同时两者的生命周期也稍微有些不同。
1.最基本的容器 //注入数据
2.更多功能的容器 //拦截器、WebApplicationContext,国际化等
事件传播
资源访问
国际化
生命周期的区别?
有一点点区别。后者包括了前者的的生命周期。
拦截器是ApplicationContext提供的功能吗?
是的。除了拦截器,还有WebApplicationContext 即web功能,都是。因为前者是在早期出来的容器框架,只负责解决最核心的问题,那就是注入数据的问题,其他的问题都是后来添加解决的。
参考
1.
首先两者加载Bean的方式都是通过Xml配置文件,ApplicationContext和BeanFacotry相比,提供了更多的扩展功能,但是这还不是主要区别,主要区别在于BeanFacotry是延迟加载,举个例子:如果Bean没有完全注入,BeanFacotry加载后,会在你第一次调用GetBean方法才会抛出异常;而ApplicationContext会在初始化的时候就加载并且检查,这样的好处是可以及时检查依赖是否完全注入;所以通常来说我们会选择使用ApplicationContext。
BeanFactory和ApplicationContext都支持BeanPostProcessor、BeanFactoryPostProcessor的使用,但两者之间的区别是:BeanFactory需要手动注册,而ApplicationContext则是自动注册。
BeanFacotry是Spring中相当古老的Factory了,比如说Xml BeanFactory就是一种相当典型的BeanFactory。所以原始的BeanFactory就无法支持诸如AOP、Web应用等许多插件。
ApplicationContext接口是由BeanFactory接口派生出来的,所以提供了BeanFactory的所有功能。ApplicationContext是一种更加面向框架的工作方式以及对上下文进行分层和实现继承。并且ApplicationContext还额外的提供了以下功能:
• MessageSource,提供国际化的消息访问;
• 资源访问,如URL和文件;
• 事件传播;
• 载入多个(有继承关系)上下文,使得每一个上下文都专注于一个特定的层次,比如应用的Web层。
2.官方文档API
Central interface to provide configuration for an application. This is read-only while the application is running, but may be reloaded if the implementation supports this.
An ApplicationContext provides:
Bean factory methods for accessing application components. Inherited from ListableBeanFactory. The ability to load file resources in a generic fashion. Inherited from the ResourceLoader interface. The ability to publish events to registered listeners. Inherited from the ApplicationEventPublisher interface. The ability to resolve messages, supporting internationalization. Inherited from the MessageSource interface. Inheritance from a parent context. Definitions in a descendant context will always take priority. This means, for example, that a single parent context can be used by an entire web application, while each servlet has its own child context that is independent of that of any other servlet. In addition to standard BeanFactory lifecycle capabilities, ApplicationContext implementations detect and invoke ApplicationContextAware beans as well as ResourceLoaderAware, ApplicationEventPublisherAware and MessageSourceAware beans.
3.Sping的容器可以分为两种类型 :1. BeanFactory:(org.springframework.beans.factory.BeanFactory接口定义)是最简答的容器,提供了基本的DI支持。最常用的BeanFactory实现就是XmlBeanFactory类,它根据XML文件中的定义加载beans,该容器从XML文件读取配置元数据并用它去创建一个完全配置的系统或应用。 2. ApplicationContext应用上下文:org.springframework.context.ApplicationContext)基于BeanFactory之上构建,并提供面向应用的服务。
作者:朱小厮 来源:CSDN 原文:blog.csdn.net/u013256816/… 版权声明:本文为博主原创文章,转载请附上博文链接!
如何获取/得到应用程序上下文/spring容器?
不管是简单java项目容器,还是复杂web项目容器,想要获取spring容器/应用程序上下文的方法是一样的,有两种:
1.从项目类路径
2.从磁盘指定路径
只不过web项目还多了一种,就是从web项目配置文件目录路径读取配置文件。
注意,读取配置文件和创建应用程序上下文/spring容器是一起同时完成的,因为我们就是使用:容器 容器对象 = new 容器类(配置文件); 这种方式来获取容器/应用程序上下文的。
spring-应用程序上下文类是什么?以及与servlet的ServletContext的区别?
1.servlet
应用程序上下文类是哪个?ServletContext。怎么获取?init()或service()的输入参数就是ServletContext或者可以通过输入参数来获取到ServletContext。
2.spring
应用程序上下文类是哪个?ApplicationContext=spring容器。
工作使用
比如支付系统,其他公司其他项目差不多。具体是?一般在控制器的基类里获取,
代码
request.getContext(); //基本上都是类似这样的代码,就是本质上是可以使得每个请求都能获取到应用程序上下文。这个原理其实是不分是servlet还是struts2还是spring,原理一致。
spring bean 生命周期
一般来说,一个对象的生命周期,主要就是下面三步
1.init()
初始化。比如,写日志或别的初始化任务,等等。
2.service()
业务
3.destroy()
释放资源
不管,这个对象是spring bean,还是servlet类,还是普通的一般对象。都是一样。
servlet生命周期
1.初始化方法、静态数据
都是第一次被访问时,才进入该类,才执行静态数据——》初始化方法;
如果是配置了启动服务器立即加载该servlet类,那么就在启动服务器时就进入该类,就执行静态数据——》初始化方法
注:都只执行一次,以后被访问不再执行,除非重启服务器!
延伸:过滤器的生命周期,也就是说是指过滤器类的生命周期?
1.init方法:在启动服务器的时候,就执行init(过滤器配置)方法,并且只执行一次
2.业务方法:每次请求每次执行
3.销毁方法:关闭服务器的时候,才执行,并且只执行一次(当然只执行一次了,都关闭了还怎么执行)
spring bean的生命周期
类似servlet的生命周期:也有初始化方法和销毁方法。
生命周期的细节
Bean是如何被管理的?
在Spring框架中,一旦把一个bean纳入到Spring IoC容器之中,这个bean的生命周期就会交由容器进行管理,一般担当管理者角色的是BeanFactory或ApplicationContext。认识一下Bean的生命周期活动,对更好的利用它有很大的帮助。
概括来说主要有四个阶段:根据配置文件或注解 加载/实例化,初始化,使用,销毁。
Spring 只帮我们管理单例模式 Bean 的完整生命周期,对于 prototype 的 bean ,Spring 在创建好交给使用者之后则不会再管理后续的生命周期。
面试题-如何在加载bean之前写日志?
init方法。
写日志,或别的初始化任务。
参考
www.cnblogs.com/zrtqsk/p/37…
作用域和单例/多例
作用域
类似servlet的生命周期
有请求范围作用域和会话范围作用域。
注意,在spring里,作用域和单例/多例有密切的关系,具体什么关系?看下面。
单例和多例
单例:不管在任何地方,每次注入的数据都是同一个对象。
多例-请求:每个请求,创建一个新的实例。但是,同一个请求,共用一个实例。
多例-会话:同上。
多例-原型:每次注入/创建的都是一个新的对象。
具体配置方法
scope属性配置值即可。
会话-应用场景
购物车,每个用户的购物车是基于会话,每个会话/购物车都有自己的实例。
Spring框架中的单例bean是线程安全的吗?
不,Spring框架中的单例bean不是线程安全的,因为只要是单例,那么多线程情况下肯定不安全。一般bean都有依赖bean,但是依赖bean一般都没有数据;如果实在要带数据,可以使用ThreadLocal。
注入数据
有三种方式
1.基于配置文件
2.基于java注解
3.基于自动扫描
基于一次性配置扫描scan + 正则表达式匹配。
优点是不用每次都配置或注解。
spring-事务
Spring 是如何管理事务的?
spring的事务声明有两种方式,编程式(硬编码/代码)和声明式(配置文件或注解声明)。spring主要是通过“声明式事务”的方式对事务进行管理,即在配置文件中进行声明,通过AOP将事务切面切入程序,最大的好处是大大减少了代码量。
Spring支持两种类型的事务管理:
编程式事务管理:这意味你通过编程的方式管理事务,给你带来极大的灵活性,但是难维护。 声明式事务管理:这意味着你可以将业务代码和事务管理分离,你只需用注解和XML配置来管理事务。
Spring 事务中的隔离级别有哪几种?
TransactionDefinition 接口中定义了五个表示隔离级别的常量:
TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别. TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读 TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生 TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。 TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。
总结
和数据库本身的四种隔离级别一样。
事务-传播规则
Spring 事务中哪几种事务传播行为?
支持当前事务的情况:
TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。 TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。 TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性) 不支持当前事务的情况:
TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。 TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。 TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。 其他情况:
TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。
总结
1.按是否支持事务划分
2.按是否创建新的事务划分
最佳实践,一般都是支持事务,并且复用同一个事务。
拦截器
应用场景
事务、日志、安全性等。
拦截器的生命周期
也是和bean差不多
1.init()
2.service()
3.destroy()
常用注解
Spring中如何使用注解来配置Bean?有哪些相关的注解?
答:首先需要在Spring配置文件中增加如下配置:
<context:component-scan base-package="org.example"/>。
然后可以用@Component、@Controller、@Service、@Repository注解来标注需要由Spring IoC容器进行对象托管的类。这几个注解没有本质区别,只不过@Controller通常用于控制器,@Service通常用于业务逻辑类,@Repository通常用于仓储类(例如我们的DAO实现类),普通的类用@Component来标注。
除此之外,还有service类的方法,经常会使用事务注解@Trancation,因为service类的业务方法通常包含了多个不同dao类的多个sql。
springMVC的处理流程-也就是请求和响应流程
Spring MVC的工作原理是怎样的?
Spring MVC的工作原理如下图所示:
① 客户端的所有请求都交给前端控制器DispatcherServlet来处理,它会负责调用系统的其他模块来真正处理用户的请求。
② DispatcherServlet收到请求后,将根据请求的信息(包括URL、HTTP协议方法、请求头、请求参数、Cookie等)以及HandlerMapping的配置找到处理该请求的Handler(任何一个对象都可以作为请求的Handler)。
③在这个地方Spring会通过HandlerAdapter对该处理器进行封装。
④ HandlerAdapter是一个适配器,它用统一的接口对各种Handler中的方法进行调用。
⑤ Handler完成对用户请求的处理后,会返回一个ModelAndView对象给DispatcherServlet,ModelAndView顾名思义,包含了数据模型以及相应的视图的信息。
⑥ ModelAndView的视图是逻辑视图,DispatcherServlet还要借助ViewResolver完成从逻辑视图到真实视图对象的解析工作。
⑦ 当得到真正的视图对象后,DispatcherServlet会利用视图对象对模型数据进行渲染。 ⑧ 客户端得到响应,可能是一个普通的HTML页面,也可以是XML或JSON字符串,还可以是一张图片或者一个PDF文件。
什么是Spring的MVC框架?
Spring 配备构建Web 应用的全功能MVC框架。Spring可以很便捷地和其他MVC框架集成,如Struts,Spring 的MVC框架用控制反转把业务对象和控制逻辑清晰地隔离。它也允许以声明的方式把请求参数和业务对象绑定。
DispatcherServlet
Spring的MVC框架是围绕DispatcherServlet来设计的,它用来处理所有的HTTP请求和响应。
WebApplicationContext
WebApplicationContext 继承了ApplicationContext 并增加了一些WEB应用必备的特有功能,它不同于一般的ApplicationContext ,因为它能处理主题,并找到被关联的servlet。
拦截器
不同的地方,不同的叫法
1.servlet
叫过滤器filter
2.struts
叫拦截器intercepter
3.spring
叫面向切面AOP(Aspect Oriented Programming面向切面编程)
但是,本质上都一样,就是为了提高拦截器的功能,把方法拦截下来,然后在之前和在之后做点什么通用的事情。
spring
只不过在spring里叫切面Aspect,字面意思就是横向切一刀的意思,也还算是比较形象。
具体如何使用?
1.配置切面
哪些包/类需要拦截;
从何处拦截;
拦截之后和之前,分别做点什么
2.给切面类加上注解@Aspect
Aspect 切面
AOP核心就是切面,它将多个类的通用行为封装成可重用的模块,该模块含有一组API提供横切功能。比如,一个日志模块可以被称作日志的AOP切面。根据需求的不同,一个应用程序可以有若干切面。在Spring AOP中,切面通过带有@Aspect注解的类实现。
在Spring AOP 中,关注点和横切关注的区别是什么?
关注点是应用中一个模块的行为,一个关注点可能会被定义成一个我们想实现的一个功能。横切关注点是一个关注点,此关注点是整个应用都会使用的功能,并影响整个应用,比如日志,安全和数据传输,几乎应用的每个模块都需要的功能。因此这些都属于横切关注点。
连接点
连接点代表一个应用程序的某个位置,在这个位置我们可以插入一个AOP切面,它实际上是个应用程序执行Spring AOP的位置。
通知
通知是个在方法执行前或执行后要做的动作,实际上是程序执行时要通过SpringAOP框架触发的代码段。
Spring切面可以应用五种类型的通知:
before:前置通知,在一个方法执行前被调用。
after: 在方法执行之后调用的通知,无论方法执行是否成功。
after-returning: 仅当方法成功完成后执行的通知。
after-throwing: 在方法抛出异常退出时执行的通知。
around: 在方法执行之前和之后调用的通知。
切点
切入点是一个或一组连接点,通知将在这些位置执行。可以通过表达式或匹配的方式指明切入点。
什么是引入?
引入允许我们在已存在的类中增加新的方法和属性。
什么是目标对象?
被一个或者多个切面所通知的对象。它通常是一个代理对象。也指被通知(advised)对象。
什么是代理?
代理是通知目标对象后创建的对象。从客户端的角度看,代理对象和目标对象是一样的。
有几种不同类型的自动代理?*
BeanNameAutoProxyCreator DefaultAdvisorAutoProxyCreator Metadata autoproxying
什么是织入。什么是织入应用的不同点?
织入是将切面和到其他应用类型或对象连接或创建一个被通知对象的过程。
织入可以在编译时,加载时,或运行时完成。
spring-AOP:如何实现事务?
我们常说,AOP可以实现日志、安全、事务。如何实现事务?
1.首先,我们得理解什么是事务,数据库事务就是
1)begin //创建连接
2)sql1
3)sql2 //多个sql原子执行
4)end //commit
2.具体到我们代码里就是这样
@Reposity注解 //注解的作用就是标识原子提交事务 //注解的实现?就是AOP。
方法(){
sql1
sql2 //多个sql原子提交
}
3.AOP实现数据库事务
就是一个拦截器,在执行事务注解的方法时,相当于
1)begin //创建连接
2)业务方法()
3)end //commit
总结
弄懂了步骤和流程,就基本上理解了实现原理。其实本质上就是使用AOP技术封装了一下数据库事务的操作流程步骤,对使用层面是透明的,我们只需要添加一个注解,就可以完成数据库事务的功能,底层实现都由spring AOP和持久层框架封装好了。
参考
spring in action