⼀篇⽂章讲透springioc(概念、原理、实例、应⽤场景、⾯试
题)
ioc概念
优势
原理
常见api
实例
应⽤场景
常见⾯试题
ioc概念、优势、原理、常见使⽤、实例、应⽤场景
ioc概念与定义:ioc翻译成中⽂为控制反转。意思可以理解为类与类之间的依赖通过容器来控制、配置实
现;换⼀种⽅式可以这么理解原来类与类之间在编译时即产⽣了依赖,即new 对象时,已建⽴好两者之间的依赖关系;ioc机制将两者之间的依赖关系通过容器进⾏控制,通过注解的⽅式,在运⾏时阶段,动态的将某种依赖注⼊到类当中。
优势:
减少了代码之间的耦合度
增强了类的扩展性
简化配置,提⾼代码复⽤性
原理:ioc主要是通过反射原理实现 ,设计流程如下:
ioc反射原理实现
流程解析:
1. 根据路径、资源名称等⽅式,将xml⽂件、注解类加载到容器中
2. 通过BeanDefinitionReader将对象解析成BeanDefinition实例
3. 创建BeanFactory⼯⼚(注册前后需要添加bean前置、后置处理器)
4. 通过BeanFactory⼯⼚将对象实例化、对象初始化(初始化前后执⾏前置、后置处理器)
核⼼类解析:
BeanDefinition:
bean定义类,定义了bean内部的组成⽅式(例如class、properties、autoware等)  配置的xml⽂件,annotation类的
注解都基于此定义类实现。 容器中的每⼀个 bean 都会有⼀个对应的 BeanDefinition 实例。该实例负责保存 bean 对象的所有必要信息,包括 bean 对象的 class 类型、是否是抽象类、构造⽅法和参数、
其他属性等等。
BeanDefinitionReader:  加载、解析资源
bean定义类读取接⼝:定义上⽂BeanDefinition实例的读取⽅式。通过获取类加载器、⽂件路径资源等⽅式读取实例所在的xml⽂件或者java类,将其加载到虚拟机中。最终将其解析成为BeanDefinition实例对象
BeanFactory
spring Bean处理的主⼊⼝,负责Bean的创建与管理。 常见使⽤例如  ApplicationContext、ClassPathXmlApplicationContext 即是其中的实例
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// 创建bean⼯⼚,读取xml⽂件,加载beanDefinitions到缓存中
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// bean⼯⼚前置处理
prepareBeanFactory(beanFactory);
try {
注册bean⼯⼚处理器
postProcessBeanFactory(beanFactory);
//执⾏bean⼯⼚
invokeBeanFactoryPostProcessors(beanFactory);
// 注册bean处理器
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// 初始化容器事件⼴播
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// 注册事件
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
BeanFactoryPostProcessor
BeanFactory级别的处理,是针对整个Bean的⼯⼚进⾏处理,在bean⼯⼚初始化前后进⾏处理。
BeanPostProcessor
bean级别的处理,针对某个具体的bean进⾏处理。在bean初始化操作的前后进⾏处理
常见api :
@Controller
⽤于标注控制器层组件
@Service
⽤于标注业务层组件
@Component
⽤于标注这是⼀个受 Spring 管理的组件,组件引⽤名称是类名,第⼀个字母⼩写。可以使⽤@Component(“beanID”) 指定组件的名称
@Repository
⽤于标注数据访问组件,即DAO组件
@Auwared
⽅法级别的注解,主要⽤在@Configuration和@Component注解的类⾥,@Bean注解的⽅法会产⽣⼀个Bean对象,该对象由
Spring管理并放到IoC容器中。引⽤名称是⽅法名,也可以⽤@Bean(name = "beanID")指定组件名
@Resource
默认按名称进⾏⾃动装配,当不到与名称匹配的Bean时会按类型装配。
@Scope("protoype")
将组件的范围设置为原型的(即多例)。保证每⼀个请求有⼀个单独的action来处理,避免action的线程问题。
常见⾯试题 :
1、Spring是什么?
Spring是⼀个轻量级的IoC和AOP容器框架。⽬的是解决企业应⽤开发的复杂性,使⽤基本的JavaBean来完成以前只可能由EJB完成的事情,并提供了更多的企业应⽤功能,Spring的⽤途不仅限
于服务器端的开发,从简单性、可测试性和松耦合的⾓度⽽⾔,任何Java应⽤都可以从Spring中受益。
2、Spring 的优点?
(1)spring属于低侵⼊式设计,代码的污染极低;
(2)spring的DI机制降低了业务对象替换的复杂性;
(3)容器提供了AOP技术,利⽤它很容易实现如权限拦截,运⾏期监控等功能;
(4)降低了组件之间的耦合性 ,实现了软件各层之间的解耦;
(5)容器提供单例模式⽀持;
(6)可以使⽤容器提供的众多服务,如事务管理,消息服务等;
(7)容器提供了众多的辅助类,能加快应⽤的开发;
(8)spring对于主流的应⽤框架提供了集成⽀持,如hibernate,JPA,Struts等
(9)独⽴于各种应⽤服务器
(10)Spring的⾼度开放性,并不强制应⽤完全依赖于Spring,开发者可以⾃由选择spring的部分或全部。
4、Spring的IoC理解:
(1)IOC就是控制反转。就是对象的创建权反转交给Spring,由容器控制程序之间的依赖关系,作⽤是实现了程序的解耦合,⽽⾮传统实现中,由程序代码直接操控。(依赖)控制权由应⽤代码本⾝转到了外部容器,由容器根据配置⽂件去创建实例并管理各个实例之间的依赖关系,控制权的转移,是所谓反转,并且由容器动态的将某种依赖关系注⼊到组件之中。BeanFactory 是Spring IoC容器的具体实现与核⼼接⼝,提供了⼀个先进的配置机制,使得任何类型的对象的配置成为可能,⽤来包装和管理各种bean。
(2)最直观的表达就是,IOC让对象的创建不⽤去new了,可以由spring⾃动⽣产,这⾥⽤的就是java的反射机制,通过反射在运⾏时动态的去创建、调⽤对象。spring就是根据配置⽂件在运⾏时动态的去创建对象,并调⽤对象的⽅法的。
(3)Spring的IOC有三种注⼊⽅式 :
第⼀是根据属性注⼊,也叫set⽅法注⼊;
第⼆种是根据构造⽅法进⾏注⼊;
第三种是根据注解进⾏注⼊。
详细的说:
(4)IoC,控制反转:将对象交给容器管理,你只需要在spring配置⽂件总配置相应的bean,以及设置相关的属性,让spring容器⽣成类的实例对象以及管理对象。在spring容器启动的时候,spring会把你在配置⽂件中配置的bean都初始化以及装配好,然后在你需要调⽤的时候,就把它已经初始化好的那些bean分配给你需要调⽤这些bean的类。就是将对象的控制权反转给spring容器管理。(5)DI机制(Dependency Injection,依赖注⼊):可以说是IoC的其中⼀个内容,在容器实例化对象的时候主动的将被调⽤者(或者说它的依赖对象)注⼊给调⽤对象。⽐如对象A需要操作数据库,以前我们总是要在A中⾃⼰编写代码来获得⼀个Connection对象,有了 spring我们就只需要告诉spring,A中需要⼀个Connection,⾄于这个Connection怎么构造,何时构造,A不需要知道。在系统运⾏时,spring会在适当的时候制造⼀个Connection,然后像打针⼀样,注射到A当中,这样就完成了对各个对象之间关系的控制。
IoC让相互协作的组件保持松散的耦合,⽽AOP编程允许你把遍布于应⽤各层的功能分离出来形成可重⽤的功能组件。
spring ioc注解
5、BeanFactory和ApplicationContext有什么区别?
BeanFactory和ApplicationContext是Spring的两⼤核⼼接⼝,⽽其中ApplicationContext是BeanFactory的⼦接⼝。它们都可以当做Spring的容器,⽣成Bean实例的,并管理容器中的Bean。
(1)BeanFactory:是Spring⾥⾯最底层的接⼝,提供了最简单的容器的功能,负责读取bean配置⽂档,管理bean的加载与实例化,维护bean之间的依赖关系,负责bean的⽣命周期,但是⽆法⽀持spring的aop功能和web应⽤。
(2)ApplicationContext接⼝作为BeanFactory的派⽣,因⽽具有BeanFactory所有的功能。⽽且ApplicationContext还在功能上做了扩展,以⼀种更⾯向框架的⽅式⼯作以及对上下⽂进⾏分层和实现继承,相较于BeanFactorty,ApplicationContext还提供了以下的功能:
①默认初始化所有的Singleton,也可以通过配置取消预初始化。
②继承MessageSource,因此⽀持国际化。
③资源访问,⽐如访问URL和⽂件。
④事件机制。
⑤同时加载多个配置⽂件。
⑥以声明式⽅式启动并创建Spring容器。
⑦载⼊多个(有继承关系)上下⽂ ,使得每⼀个上下⽂都专注于⼀个特定的层次,⽐如应⽤的web层。
(3)①BeanFactroy采⽤的是延迟加载形式来注⼊Bean的,即只有在使⽤到某个Bean时(调⽤getBean()),才对该Bean进⾏加载实例化,这样,我们就不能发现⼀些存在的Spring的配置问题。如果Bean的某⼀个属性没有注⼊,BeanFacotry加载后,直⾄第⼀次使⽤调⽤getBean⽅法才会抛出异常。
②⽽ApplicationContext则相反,它是在容器启动时,⼀次性创建了所有的Bean。这样,在容器启动时,我们就可以发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注⼊。 ApplicationContext启动后预载⼊所有的单实例Bean,通过预载⼊单实例bean ,确保当你需要的时候,你就不⽤等待,因为它们已经创建好了。
③相对于基本的BeanFactory,ApplicationContext 唯⼀的不⾜是占⽤内存空间。当应⽤程序配置Bean较多时,程序启动较慢。(4)BeanFactory通常以编程的⽅式被创建,ApplicationContext还能以声明的⽅式创建,如使⽤ContextLoader。
(5)BeanFactory和ApplicationContext都⽀持BeanPostProcessor、BeanFactoryPostProcessor的使⽤,但两者之间的区别是:BeanFactory需要⼿动注册,⽽ApplicationContext则是⾃动注册。
6、 解释Spring⽀持的⼏种bean的作⽤域。
Spring容器中的bean可以分为5个范围:
(1)singleton:这种bean范围是默认的,这种范围确保不管接受到多少个请求,每个容器中只有⼀个bean的实例,单例的模式由bean factory⾃⾝来维护。
(2)prototype:原形范围与单例范围相反,为每⼀个bean请求提供⼀个实例。
(3)request:在请求bean范围内会每⼀个来⾃客户端的⽹络请求创建⼀个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
(4)Session:与请求范围类似,确保每个session中有⼀个bean的实例,在session过期后,bean会随之失效。
(5)global-session:global-session和Portlet应⽤相关。当你的应⽤部署在Portlet容器中⼯作时,它包含很多portlet。如果你想要声明让所有的portlet共⽤全局的存储变量的话,那么这全局变量需要存储在global-session中。全局作⽤域与Servlet中的session 作⽤域效果相同。
7、请解释Spring Bean的⽣命周期?
⾸先说⼀下Servlet的⽣命周期:实例化,初始init,接收请求service,销毁destroy;
Spring上下⽂中的Bean⽣命周期也类似,如下:
(1)实例化⼀个Bean--也就是我们常说的new;
(2)按照Spring上下⽂对实例化的Bean进⾏配置--也就是IOC注⼊;
(3)如果这个Bean已经实现了BeanNameAware接⼝,会调⽤它实现的setBeanName(String)⽅法,此处传递的就是Spring配置⽂件中Bean的id值;
(4)如果这个Bean已经实现了BeanFactoryAware接⼝,会调⽤它实现的setBeanFactory(setBeanFactory(BeanFactory)传递的是Spring⼯⼚⾃⾝(可以⽤这个⽅式来获取其它Bean,只需在Spring配置⽂件中配置⼀个普通的Bean就可以);
(5)如果这个Bean已经实现了ApplicationContextAware接⼝,会调⽤setApplicationContext(ApplicationContext)⽅法,传⼊Spring上下⽂(同样这个⽅式也可以实现步骤4的内容,但⽐4更好,因为ApplicationContext是BeanFactory的⼦接⼝,有更多的实现⽅法);
(6)如果这个Bean关联了BeanPostProcessor接⼝,将会调⽤postProcessBeforeInitialization(Object obj, String s)⽅
法,BeanPostProcessor经常被⽤作是Bean内容的更改,并且由于这个是在Bean初始化结束时调⽤那个的⽅法,也可以被应⽤于内存或缓存技术;
(7)如果Bean在Spring配置⽂件中配置了init-method属性会⾃动调⽤其配置的初始化⽅法。
(8)如果这个Bean关联了BeanPostProcessor接⼝,将会调⽤postProcessAfterInitialization(Object obj, String s)⽅法、;注:以上⼯作完成以后就可以应⽤这个Bean了,那这个Bean是⼀个Singleton的,所以⼀般情况下我们调⽤同⼀个id的Bean会是在内容地址相同的实例,当然在Spring配置⽂件中也可以配置⾮Singleton。
(9)当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接⼝,会调⽤那个其实现的destroy()⽅法;(10)最后,如果这个Bean的Spring配置中配置了destroy-method属性,会⾃动调⽤其配置的销毁⽅法。
另外我们这⾥描述的是应⽤Spring上下⽂Bean的⽣命周期,如果应⽤Spring的⼯⼚也就是BeanFactory的话去掉第5步就Ok了。
8、Spring中bean的加载过程:
(1)获取配置⽂件资源;
(2)对获取的xml资源进⾏⼀定的处理检验;
(3)处理包装资源;
(4)解析处理包装过后的资源;
(5)加载提取bean并注册(添加到beanDefinitionMap中)。
9、Spring框架中的单例Beans是线程安全的么?
Spring框架并没有对单例bean进⾏任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者⾃⾏去搞定。但实际上,

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