一、Spring 学习
2、Spring Ioc容器和Beans概述
IoC(Inversion of Control,控制倒转),可以说是spring最核心的部分,是spring家族任意组件的基本。Ioc 本身并不能算为一种技术,而是一种思想,它使你从繁琐的对象交互中解脱出来,而专注于对象本身,更进一步突出面向对象。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。
DI(Dependency Injection,依赖注入)是目前使用较多的IOC实现方式, 常用的有两种方法:构造方法注入和setter注入。
构造注入:
<bean class="com.tcwong.bean.Cat" id="catId">
<constructor-arg name="name" value="小黑"></constructor-arg>
<constructor-arg name="color" value="嘿嘿"></constructor-arg>
</bean>'
setter注入:
<bean class="com.tcwong.bean.User">
<property name="name" value="su"></property>
<property name="age" value="20"></property>
<property name="cats">
<array>
<bean class="com.tcwong.bean.Cat" >
<constructor-arg name="name" value="tom"></constructor-arg>
<constructor-arg name="color" value="白色"></constructor-arg>
</bean>
</array>
</property>
<property name="list">
<list>
<value>好好学习</value>
<value>天天向上</value>
<value>明天会更好</value>
</list>
</property>
<property name="map">
<map>
<entry key="上学" value="交学费"></entry>
<entry key="放学" value="写作业"></entry>
<entry key="cat" value-ref="catId"></entry>
</map>
</property>
<property name="props">
<props>
<prop key="date">1992</prop>
<prop key="important">生日快乐</prop>
</props>
</property>
</bean>
2.1、 IOC容器
Ioc需要实现两个技术:完成对象的构建,将其送到服务对象即完成对象的绑定。Spring提供了两种类型的容器,一个是BeanFactory,一个是ApplicationContext(可以认为是BeanFactory的扩展)。
①BeanFactory
如果没有特殊指定,默认采用延迟初始化策略(lazy-load)。只有当客户端对象需要访问容器中的某个受管对象的时候,才对该受管对象进行初始化以及依赖注入操作。所以,相对来说,容器启动初期速度较快,所需 要的资源有限。对于资源有限,并且功能要求不是很严格的场景,BeanFactory是比较合适的 IoC容器选择。我们先来看一下BeanFactory类的关系图(如下所示)
有三个很重要的部分:
- BeanDefinition 实现Bean的定义(即对象的定义),且完成了对依赖的定义
- BeanDefinitionRegistry ,将定义好的bean,注册到容器中(此时会生成一个注册码)
- BeanFactory 是一个bean工厂类,从中可以取到任意定义过的bean最重要的部分就是BeanDefinition,它完成了Bean的生成过程。一般情况下我们都是通过配置文件(xml,properties)的方式对bean进行配置,每种文件都需要实现BeanDefinitionReader,因此是reader本身现了配置文字 到bean对象的转换过程。当然我们自己也可以实现任意格式的配置文件,只需要自己来实现reader即可。Bean的生成大致可以分为两个阶段:容器启动阶段和bean实例化阶段
容器启动阶段:
- 加载配置文件(通常是xml文件)
- 通过reader生成beandefinition
- beanDefinition注册到beanDefinitionRegistry
bean实例化阶段:当某个bean 被 getBean()调用时bean需要完成初时化,以及其依赖对象的初始化 如果bean本身有回调,还需要调用其相应的回调函数从 上面我们也可以知道,beanDefinition(容器启动阶段)只完成bean的定义,并未完成初始化。初始是通过beanFactory的getBean()时才进行的。Spring Ioc在初始化完成之后,给了我们提供一些方法,让我们来改变一些bean的定义org.springframework.beans.factory.config.PropertyPlaceholderConfigurer:使我们可能通过配置文件的形式,配置一些参数PropertyOverrideConfigurer :则可以覆盖原本的bean参数CustomEditorConfigurer :则提供类型转换支持(配置文件都是string,它需要知道转换成何种类型)Bean的初始化过程:
如果你认为实例化的对象就是通过我们定义的类new 出来的,那就大错特错了,其实这里用到了AOP机制,生成了其代理对象(通过反射机制生成接口对象,或者是通过CGLIB生成子对象)bean的具体装载过程是由beanWrapper实现的,它继承了PropertyAccessor (可以对属性进行访问)、PropertyEditorRegistry 和TypeConverter接口 (实现类型转换,就上前面说的)。完成设置对象属性之后,则会检查是否实现了Aware类型的接口,如果实现了,则主动加载。
BeanPostprocessor 可以帮助完成在初始化bean之前或之后 帮我们完成一些必要工作,比如我们在连接数据库之前将密码存放在一个加密文件,当我们连接数据库之前,需要将密码进行加载解密。只要实现相应的接口即可。
在完成postProcessor之后,则会看对象是否定义了InitializingBean 接口,如果是,则会调用其afterProper- tiesSet()方法进一步调整对象实例的状态 ,这种方式并不常见。spring还提供了另外一种指定初始化的方式,即在bean定义中指定init-method 。当这一切完成之后,还可以指定对象销毁 的一些回调,比如数据库的连接池的配置,则销毁前需要关闭连接等。相应的可以实现DisposableBean 接口或指定destroy-method。
② ApplicationContext
ApplicationContext 容器建立BeanFactory之上,拥有BeanFactory的所有功能:
- 1.bean的生成方式;
- 2.扩展了BeanFactory的功能,提供了更多企业级功能的支持。
1.bean的加载方式BeanFactory提供BeanReader来从配置文件中读取bean配置。相应的ApplicationContext也提供几个读取配置文件的方式:
- FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你需要提供给构造器 XML 文件的完整路径
- ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不需要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量即可,因为,容器会从 CLASSPATH 中搜索 bean 配置文件。
- WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。
- AnnotationConfigApplicationContext
- ConfigurableWebApplicationContext另外一个比较重要的是,ApplicationContext采用的非懒加载方式。它会在启动阶段完成所有的初始化,并不会等到getBean()才执行。所以,相对于BeanFactory来 说,ApplicationContext要求更多的系统资源,同时,因为在启动时就完成所有初始化,容 器启动时间较之BeanFactory也会长一些。在那些系统资源充足,并且要求更多功能的场景中, ApplicationContext类型的容器是比较合适的选择。