在理解任何技术以前,我都会问本身一个问题:它的产生是为了解决什么样的问题,以及如何解决这些问题?但愿你能在本篇文章中找到答案……
(因为你们对Ioc应该是常用了,因此这里不会告诉你应该怎么样使用,重要的是理解思想原理,理解过程)javascript
IoC能够说是spring最核心的部分,是spring家族任意组件的基本。Ioc 自己并不能算为一种技术,而是一种思想,它使你从繁琐的对象交互中解脱出来,而专一于对象自己,更进一步突出面向对象。
咱们先来回答文章开头问题的上半部分:
咱们假设一个场景:Person(人)天天都要吃早餐(食物)。咱们能够用以下程序表示html
public class Person {
public void eat() {
Food food = new food();
System.out.println("I eat food:{}", food.toString());
}
}复制代码
在咱们吃饭以前必须先new food()(作饭),要否则就吃不上。
Ioc 会怎么样作呢java
public class Person {
private Food food;
public void eat() {
System.out.println("I eat food:{}", food.toString());
}
}复制代码
它会在你吃的时候将食物准备好,不须要你本身作饭。由于它认为:吃饭的人不该该身兼厨师的角色。
借用《spring 揭秘》中的漫画再说明一下吧(由于我不会画吃饭的漫画)。它的意思是:穿衣服出门。若是不使用Ioc,你就得本身去取衣服穿上。用了IOC,已经有美女给你拿过来并帮你穿上(有没有一种大款的感受)。IOC就是让你当大款,你只须要发挥本身的特长挣钱就能够了,其它的让小秘来。
web
接下来的问题是如何将依赖的对象准备好呢(依赖注入),经常使用的有两种方式:构造方法注入和setter注入(虽然你们都很熟悉了,但还请原谅我再说一下)
构造器注入,它就表明了当Person这个对象生成时,就准备好了:即不管你吃不吃饭,饭就在那里,不离不弃spring
public Person(Food food) {
this.food = food;
}复制代码
setter注入,有所不一样:俺不是那么随便的食物,你得喊我(set)俺才过来,有种闷骚的感受。反正我就喜欢这种……数据库
public void setFood(Food food) {
this.food = food;
}复制代码
但不管前提哪种注入方法,你总得有小秘来执行吧!!!so,你只须要默默地躺在那来享受,小秘带来百般绝技!!!app
小秘绝技虽然精彩,但要实现却并不那么容易。它须要一系列技术要实现。首先它须要知道服务的对象是谁,以及须要为服务对象提供什么样的服务。提供的服务指:要完成对象的构建(即把饭作好),将其送到服务对象即完成对象的绑定(即把饭端到我面前)。
上面的话别看糊涂了,再声明一下,Ioc须要实现两个技术:框架
对于这两个方面技术的实现具备不少的方式:硬编码(Ioc 框架都支持),配置文件(咱们的重点),注解(最洁的方式)。但不管哪一种方式都是在Ioc容器里面实现的(咱们能够理解为一个大池子,里面躺着各类各样的对象,并能经过必定的方式将它们联系起来)
spring提供了两种类型的容器,一个是BeanFactory,一个是ApplicationContext(能够认为是BeanFactory的扩展),下面咱们将介绍这两种容器如何实现对对象的管理。ide
若是没有特殊指定,默认采用延
迟初始化策略(lazy-load)。只有当客户端对象须要访问容器中的某个受管对象的时候,才对 该受管对象进行初始化以及依赖注入操做。因此,相对来讲,容器启动初期速度较快,所需 要的资源有限。对于资源有限,而且功能要求不是很严格的场景,BeanFactory是比较合适的 IoC容器选择。
咱们先来看一下BeanFactory类的关系图(以下所示)
函数
bean实例化阶段:
当某个bean 被 getBean()调用时
bean须要完成初时化,以及其依赖对象的初始化
若是bean自己有回调,还须要调用其相应的回调函数
从 上面咱们也能够知道,beanDefinition(容器启动阶段)只完成bean的定义,并未完成初始化。初始是经过beanFactory的getBean()时才进行的。
Spring Ioc在初始化完成以后,给了咱们提供一些方法,让咱们来改变一些bean的定义
org.springframework.beans.factory.config.PropertyPlaceholderConfigurer:使咱们可能经过配置文件的形式,配置一些参数
PropertyOverrideConfigurer :则能够覆盖本来的bean参数
CustomEditorConfigurer :则提供类型转换支持(配置文件都是string,它须要知道转换成何种类型)
Bean的初始化过程:
BeanPostprocessor 能够帮助完成在初始化bean以前或以后 帮咱们完成一些必要工做,好比咱们在链接数据库以前将密码存放在一个加密文件,当咱们链接数据库以前,须要将密码进行加载解密。只要实现 相应的接口便可
public interface BeanPostProcessor {
/** * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean * initialization callbacks (like InitializingBean's {@code afterPropertiesSet} * or a custom init-method). The bean will already be populated with property values. * The returned bean instance may be a wrapper around the original. * @param bean the new bean instance * @param beanName the name of the bean * @return the bean instance to use, either the original or a wrapped one; if * {@code null}, no subsequent BeanPostProcessors will be invoked * @throws org.springframework.beans.BeansException in case of errors * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet */
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
/** * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean * initialization callbacks (like InitializingBean's {@code afterPropertiesSet} * or a custom init-method). The bean will already be populated with property values. * The returned bean instance may be a wrapper around the original. * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean * instance and the objects created by the FactoryBean (as of Spring 2.0). The * post-processor can decide whether to apply to either the FactoryBean or created * objects or both through corresponding {@code bean instanceof FactoryBean} checks. * <p>This callback will also be invoked after a short-circuiting triggered by a * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method, * in contrast to all other BeanPostProcessor callbacks. * @param bean the new bean instance * @param beanName the name of the bean * @return the bean instance to use, either the original or a wrapped one; if * {@code null}, no subsequent BeanPostProcessors will be invoked * @throws org.springframework.beans.BeansException in case of errors * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet * @see org.springframework.beans.factory.FactoryBean */
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}复制代码
在完成postProcessor以后,则会看对象是否认义了InitializingBean 接口,若是是,则会调用其afterProper- tiesSet()方法进一步调整对象实例的状态 ,这种方式并不常见。spring还提供了另一种指定初始化的方式,即在bean定义中指定init-method 。
当这一切完成以后,还能够指定对象销毁 的一些回调,好比数据库的链接池的配置,则销毁前须要关闭链接等。相应的能够实现DisposableBean 接口或指定destroy-method
ApplicationContext 容器创建BeanFactory之上,拥有BeanFactory的全部功能,但在实现上会有所差异。我认为差异主要体如今两个方面:1.bean的生成方式;2.扩展了BeanFactory的功能,提供了更多企业级功能的支持。
1.bean的加载方式
BeanFactory提供BeanReader来从配置文件中读取bean配置。相应的ApplicationContext也提供几个读取配置文件的方式:
ResourceLoader并不能将其当作是Spring独有的功能,spring Ioc只是借助于ResourceLoader来实现资源加载。也提供了各类各样的资源加载方式:
提供国际化支持,不讲了,有须要请转至:blog.sina.com.cn/s/blog_85d7…
#4、最佳实践
注解扫描
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="org.spring21"/>
</beans>复制代码
component/service/controller注解
@Component
public class Person {
@Resource
private Food food;
public void setFood(Food food) {
this.food = food;
}
}复制代码
bean的前置后置
@Component
public class Person {
@Resource
private Food food;
public setFood(Food food) {
this.food = food;
}
@PostConstruct
public void wash() {
System.out.println("饭前洗手");
}
@PreDestroy
public void brush() {
System.out.println("饭后刷牙");
}
}复制代码