`
xitongyunwei
  • 浏览: 959433 次
文章分类
社区版块
存档分类
最新评论

Spring IoC

 
阅读更多
IoC的直译是控制反转。
在IoC模式下,控制权限从应用程序转移到了IoC容器中。组件不是由应用程序负责创建和配置,而是由IoC容器负责。
使用IoC的情况下,对象是被动地接收依赖类而不是主动地查找。对象不是从容器中查找他的依赖类,而是容器在实例化对象时,主动地将他所依赖的对象注入给他。
应用程序只需要直接使用已经创建并且配置好的组件即可,而不必自己负责创建和配置。
在实际的工作中人们发现使用IoC来表述这种机制,并不是很准确甚至有些晦涩,于是引发了另外一个概念:DI(依赖注入)
目前人们认为使用依赖注入(DI—— Dependency Injection )来阐述IoC更为合适。
而事实上早在2004年初,Martin Fowler在他的站点谈论控制反转时曾提问: “问题在于,它们转变的是什么方面的控制?”。 Fowler建议重命名该原则(或至少给它一个更加明确的名称),并开始使用“依赖注入这个术语。
解析IoCDI
(一)
IoC解析
IoC(控制反转)是Spring容器的内核,AOP以及声明式事务都是在此之上完成的。IoC包括两层含义:1.控制,2反转。关键的问题在于他把什么东西的控制给反转了。
控制指组件之间的调用关系由程序自身控制(从而造成了紧耦合)。
反转是说,将这种调用关系的控制权从程序中移除,并交给第三方管理。
也就是组件的调用关系由程序自身管理转变为第三方管理,是组件依赖关系的控制权进行了反转
对于上述机制,应用IoC来描述并不准确,而且有些晦涩。
(二)
DI解析
之所以会产生组件调用,是为了获取被调用组件的功能,调用者将自己应该做的事情,委派给了被调用的对象。也就是说,调用者要完成自身的任务,必须依赖被调用的对象。这种关系实际上就是一般依赖关系(通俗点说,就是一个组件内部包含另外一个组件的实例,把该自己干的事交给自己包含的组件去完成)。因此IoC所表述的机制,实际上就是将调用者对接口实现类的依赖关系,从程序中移除,转交第三方管理实例。并且,由第三方在运行期间将调用者依赖的具体类填充进来。也就是说组件之间的依赖关系,是在程序运行期间由第三方来管理的。这个就是依赖注入的概念(DI),基于上述分析,DI比IoC更准确。
实际上就是将调用者为完成功能所依赖的实现类,在程序运行期间,由容器自动填充给调用者,这个就是依赖注入的核心思想。在依赖注入的应用中,组件并不关心被注入的对象是谁,只关系这个对象能完成的功能,也就是这个对象是哪个接口的具体类实例。
Simple Object范围:
POJO:简单的Java对象(Plain Old Java Objects)实际就是普通JavaBean
VO:value object值对象
PO:persistant object 持久对象
DTO:Data Transfer Object 数据传输对象
DAO:data access object 数据访问对象
1、注:
POJO-POJO定义:
简单的Java对象(Plain Old Java Objects)实际就是普通JavaBeans。
POJO-POJO使用:
使用POJO名称是为了不和EJB混淆起来, 而且简称比较直接. 其中有一些属性及其getter setter方法的类,有时可以作为value object或dto(Data Transform Object)来 使用.当然,如果你有一个简单的运算属性也是可以的,但不允许有业务方法,也不能携带有connection之类的方法。
2、一些名词:
PO : persistant object 持久对象
VO : value object值对象
DAO : data access object 数据访问对象
BO : business object 业务对象
POJO : plain ordinary java object 简单的java对象
DTO : Data Transfer Object 数据传输对象
1)侧重数据的对象,对象中主体是字段,字段包含数据,方法都是数据字段的getXX或setXXX等行为,没有真正意义行为。属于这种的有POJO VO PO DTO等
2)侧重功能行为的对象,和上面相反,则重方法,方法体内有很重要的行为,字段不重要。属于这种的有BO DAO JDO ADO等
DTO : Data Transfer Object 数据传输对象,主要用于远程调用等需要大量传输对象的地方。 比如我们一张表有100个字段,那么对应的PO就有100个属性。 但是我们界面上只要显示10个字段, 客户端用WEB service来获取数据,没有必要把整个PO对象传递到客户端, 这时我们就可以用只有这10个属性的DTO来传递结果到客户端,这样也不会暴露服务端表结构.到达客户端以后,如果用这个对象来对应界面显示,那此时它的身份就转为VO。
Bean是什么(一)
具有唯一id的Simple Object
由IoC容器管理其生命周期及其依赖关系
简单地讲,bean就是由Spring容器初始化、装配及被管理的对象
bean定义以及bean相互之间的依赖关系将通过配置元数据来描述
一般在XML文件中定义
1、在Spring中,那些组成应用的主体及由Spring IoC容器所管理的对象被称之为Bean。
简单地讲,bean就是由Spring容器初始化、装配及被管理的对象,除此之外,bean就没有特别之处了(与应用中的其它对象没有什么区别)。
而bean定义以及bean相互之间的依赖关系将通过配置元数据来描述。
2、JavaBean原始形态是一种符合特定规范的java对象,有无参构造器,通过get/set提供外界对私有属性的访问,是最简单最基本的java组件,即可被用作数据承载的载体即VO,也可以用来执行业务逻辑。
随着编程思维以及现实环境的发展, JavaBean的规范在实际应用中日趋模糊,日渐与POJO融合。
在Spring中,大力推荐使用的JavaBean,实际上就是POJO,凡是可以被实例化或是可以被JNDI获得的对象,都可以被Spring容器管理,都是Bean
Bean定义(二)
bean定义与应用程序中实际使用的对象一一对应。通常情况下bean的定义包括:
服务层对象
数据访问层对象(DAO)
类似Struts Action的表示层对象
Hibernate SessionFactory对象等等。
项目的复杂程度将决定bean定义的多寡。
Bean 的定义和命名(三)
使用Spring IoC容器来管理一个或多个bean,这些bean将通过配置文件中的bean定义被创建(在XML格式中为<bean/>元素)。
在容器内部,这些bean定义由BeanDefinition对象来表示,该定义将包含以下信息(在配置文件中体现为属性或子标记):
全限定类名这通常就是已定义bean的实际实现类。
bean行为的定义,即创建模式(prototype还是singleton)、自动装配模式、依赖检查模式、初始化以及销毁方法。这些定义将决定bean在容器中的行为
用于创建bean实例的构造器参数及属性值。比如使用bean来定义连接池,可以通过属性或者构造参数指定连接数,以及连接池大小限制等。
bean之间的关系,即协作 (或者称依赖)。
配置文件中Bean的基本属性(四)
Name 属性:当使用基于XML的配置元数据时,将通过id或name属性来指定bean标识符。id属性具有唯一性,而且是一个真正的XML ID属性,因此其他xml元素在引用该id时,可以利用XML解析器的验证功能。通常情况下最好为bean指定一个id。尽管XML规范规定了XML ID命名的有效字符,但是bean标识符的定义不受该限制,因为除了使用指定的XML字符来作为id,还可以为bean指定别名,要实现这一点可以在name属性中使用逗号、冒号或者空格将多个id分隔。
bean的作用域:
作用域描述singleton在每个Spring IoC容器中一个bean定义对应一个对象实例。
prototype一个bean定义对应多个对象实例。
request在一次HTTP请求中,一个bean定义对应一个实例;即每次HTTP请求将会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。
session在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。
global session在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。
BeanFactory(一)
轻量级的IoC容器
org.springframework.beans.factory.BeanFactory是Spring IoC容器的实际代表者,IoC容器负责容纳此前所描述的bean,并对bean进行管理。
管理Bean的生命周期及其依赖关系
尽可能晚的初始化Bean,适用于对内存要求很高的应用
最常用的实现是XmlBeanFactory
e.g.:BeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));
e.g.:BeanFactory factory = new XmlBeanFactory(new UrlResource("beans.xml"));
e.g.:BeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
e.g.:BeanFactory factory = new XmlBeanFactory(new ServletContextResource("beans.xml"));
key API
boolean containsBean(String)
Object getBean(String)
boolean isSingleton(String)
1、对内存要求很高:指对内存精打细算,不浪费内存的。
2、XmlBeanFactory就是最常用的一个Spring的BeanFactory的实现。该实现将以XML方式描述组成应用的对象以及对象间的依赖关系。XmlBeanFactory类将持有此XML配置元数据,并用它来构建一个完全可配置的系统或应用。
3、BeanFactory提供的方法极其简单。它仅提供了六种方法供客户代码调用:
1)boolean containsBean(String):如果BeanFactory包含给定名称的bean定义(或bean实例),则返回true.
2)Object getBean(String):返回以给定名字注册的bean实例。根据bean的配置情况,如果为singleton模式将返回一个共享的实例,否则将返回一个新建的实例。如果没有找到指定的bean,该方法可能会抛出BeansException异常(实际上将抛出NoSuchBeanDefinitionException异常),在对bean进行实例化和预处理时也可能抛出异常.
3)Object getBean(String, Class):返回以给定名称注册的bean实例,并转换为给定class类型的实例,如果转换失败,相应的异常(BeanNotOfRequiredTypeException)将被抛出。上面的getBean(String)方法也适用该规则。
4)Class getType(String name):返回给定名称的bean的Class。如果没有找到指定的bean实例,则抛出NoSuchBeanDefinitionException异常。
5)boolean isSingleton(String):判断给定名称的bean定义(或bean实例)是否为singleton模式(singleton将在bean的作用域中讨论),如果bean没找到,则抛出NoSuchBeanDefinitionException异常。
6)String[] getAliases(String):返回给定bean名称的所有别名。
ApplicationContext(二)
ApplicationContext(建议使用这种方式获取容器)
继承了BeanFactory接口,是BeanFactory功能的延伸
尽可能早的初始化Bean
支持国际化
支持事件监听机制
提供通用的方式获取资源
主要实现
ClassPathXmlApplicationContext:
从类路径下的XML文件中载入上下文定义信息
FileSystemXmlApplicationContext:
从文件系统路径下的XML文件中载入上下文定义信息
XmlWebApplicationContext:
通过ContextLoaderListener从内部导入context文件
注:
ApplicationContext與BeanFactory的區別:
spring的Ioc容器根据XML配置文件来初始化Bean.需要注意的一点是,ApplicationContext初始化Bean和基
本的BeanFactory有所不同,基本的BeanFactory总是延迟加载Bean,直到第一次调用getBean("BeanId")方法
请求Bean实例时,BeanFactory才会创建这个Bean,而ApplicationContext在自身初始化时就一次性创建了
所有的Bean,了解这一点是非常重要的,因为ApplicationContext在初始化时就能验证XML配置文件的正确性.
而使用BeanFactory,直到调用getBean("BeanId")方法获取Bean实例时,才可能会发现配置错误而导致抛出
异常.
只有在非常简单的情况下,使用基本的BeanFactory才可能满足我们的需求.绝大多时候我们使用
ApplicationContext是最佳的选择.在启动的时候就能检测配置文件的错误,这比使用基本的BeanFactory
在运行一段时间后调用getBean("BeanId")抛出异常要好得多.并且,延迟加载会带来性能上的损失.
ApplicationContext由于在启动时需要一次性别实例化所有的Bean,如果定义的Bean比较多,则启动的时间
会比较长.
ApplicationContext实例化(三)
//1、ClassPathXmlApplicationContext
String[] ctxs = new String[]{"ctx1.xml", "ctx2.xml"};
ApplicationContext ctx = new ClassPathXmlApplicationContext(ctxs);
//2、 FileSystemXmlApplicationContext
ApplicationContext ctx =
new FileSystemXmlApplicationContext("c:/beans.xml");
//3、 XmlWebApplicationContext
XmlWebApplicationContext ctx = new XmlWebApplicationContext();
ctx.setServletContext(servlet.getServletContext());
ctx.setConfigLocations(new String[] { configFile });
ctx.refresh();
获取资源(四)
默认实现
ClassPathResource:
通过 ClassPathResource 以类路径的方式进行访问;
FileSystemResource:
通过 FileSystemResource 以文件系统绝对路径的方式进行访问;
ServletContextResource:
通过 ServletContextResource 以相对于Web应用根目录的方式进行访问;
UrlResource:
通过java.net.URL来访问资源,当然它也支持File格式,如“file:”;
ApplicationContext提供了获取资源的便利途径,获取资源API:
Resource getResource(String location)
绝对路径,e.g. “file:C:/test.txt”
相对路径,e.g. “WEB-INF/test.txt”
Classpath, e.g. “classpath:test.txt”
ApplicationContextBeanFactory(五)
BeanFactory
采用延迟加载Bean,直到第一次使用getBean()方法获取Bean实例时,才会创建Bean。
ApplicationContext
ApplicationContext在自身被实例化时一次完成所有Bean的创建。大多数时候使用ApplicationContext。
区别
在服务启动时ApplicationContext就会校验XML文件的正确性,不会产生运行时bean装配错误。
BeanFactory在服务启动时,不会校验XML文件的正确性,获取bean时,如果装配错误马上就会产生异常。
1、BeanFactory提供的高级配置机制,使得管理任何性质的对象成为可能;ApplicationContext是BeanFactory的扩展,功能得到了进一步的增强,比如更易与spring AOP 集成、消息资源处理(国际化处理)、事件传递及各种不同应用层的Context实现。
2、简而言之,BeanFactory提供了配置框架功能,而ApplicationContext则增加了更多支持企业核心内容的功能。ApplicationContext完全由BeanFactory扩展而来,因而BeanFactory所具有的能力和行为也适用于ApplicationContext。
依赖注入的三种方式
设置属性注入
set注入指的就是在接受注入的类中定义一个set方法,并在参数中定义需要注入的元素。
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
public void setBeanOne(AnotherBean beanOne2) { beanOne = beanOne2; }
public void setBeanTwo(YetAnotherBean beanTwo2) { beanTwo = beanTwo2; }
}
<bean id="exampleBean" class="eg.ExampleBean">
<property name="beanOne“><ref bean="anotherExampleBean"/> </property>
<property name="beanTwo“> <ref bean="yetAnotherBean"/> </property>
</bean>
<bean id="anotherExampleBean" class="eg.AnotherBean"/>
<bean id=“yetAnotherBean” class=“eg.YetAnotherBean”/>
构造注入
构造注入指的就是在接受注入的类中定义一个构造方法,并在参数中定义需要注入的元素。
public class ExampleBean {
private AnotherBean beanOne;
private YetAnotherBean beanTwo;
public ExampleBean(AnotherBean b1, YetAnotherBean b2, int i) {
this.beanOne = b1;
this.beanTwo = b2; } }
<bean id="exampleBean" class="eg.ExampleBean">
<constructor-arg><ref bean="anotherExampleBean"/> </constructor-arg>
<constructor-arg> <ref bean="yetAnotherBean"/> </constructor-arg>
</bean>
<bean id="anotherExampleBean" class="eg.AnotherBean"/>
<bean id=“yetAnotherBean” class=“eg.YetAnotherBean”/>
1、注:使用Constructor还是Setter方法来完成依赖注入?
答:这个问题就等于在讨论一个古老的问题:要在对象建立时就准备好所有的资源,或是在对象创建好后,再使用Setter方法来进行设定。
使用Constructor的好处之一是,可以在构造对象的同时一并完成依赖关系的建立,不好的地方是,使用Constructor injection会在构造方法上留下
一长串的参数,且不易记忆,这时使用Setter方法是一个不错的选择。
然而使用Setter方法(Setter方法不许private)时,由于提供setXXX()方法,因此不能保证相关的数据成员或资源在执行时期不会被更改设定,因为程序员可能直接执行Setter方法来
设定相关的属性,所以如果想要让一些数据成员或资源变为只读或是私有,使用Constructor injection会是简单的选择。
2、存在多个构造函数时,容易引起IoC容器的混乱,需要明确告诉容器,程序中使用的是那个构造子。语法如下:
<bean id="b2" class="com.qhit.business.ioc.Business2">
<constructor-arg index="0" value="2" type="int"></constructor-arg>
<constructor-arg index="1" value="1" type="int"></constructor-arg>
</bean>
属性含义:
index :第几个参数,从零开始(一般不使用index这个属性,只根据type可以区分出使用哪个构造器)
type:参数类型
接口注入
接口注入指的就是在接口中定义要注入的信息,并通过接口完成注入。
由于接口注入的繁琐与侵入性过高,Spring没有提供对接口注入的实现。
实现不同类型属性的注入
基本类型注入
基本数据类型的注入在配置文件中直接注入即可,不需要数据类型,IoC容器会自动的根据bean中属性的类型,完成类型转换、并赋值。注入语法如下
<bean id="classes" class="com.neu.impl.Classes">
<property name="sid" value="1"/>
<property name="sname" value="貂禅"/>
</bean>
其中id表示bean在整个工程中的唯一标识,class表示该标识的引用类
property的另一种使用(子标记):
<property name="sname">
<value>貂禅</value>
</property>
Null的注入
如果某个Bean中某个属性没有值,我们应该注入null 语法如下
<property name="state">
<null/>
</property>
空字符串的注入
<bean class="ExampleBean">
<property name="email">
<value></value>
</property>
</bean>
引用类型的注入
如果我们注入的不是基本类型,而是引用类型,即对于委派关系进行注入,我们需要用<ref> 代替<value>:
<bean id="classes" class="com.neu.bean.Classes">
<property name="cid" value="1"/>
<property name="cname" value="天山"/>
</bean>
<bean id="student" class="com.neusoft.bean.Student">
<property name="sid" value="1"/>
<property name=“sname” value=“王五"/>
<property name="state" value="1"/>
<property name="classes" ref="classes"/>
</bean>
集合类型注入-set(一)
Set中基本数据类型的注入
等同于普通类中基本数据类型的注入,但是set会自动过滤重复数据。 语法如下
<property name="students">
<set>
<value>A</value>
<value>B</value>
<value>C</value>
<value>B</value>
</set>
</property>
集合类型注入-set(二)
Set中引用数据类型的注入
如果属性承载的也是对bean 引用,在set内部等同于对象的引用 语法如下
<property name="students">
<set>
<ref bean="stu1"/>
<ref bean="stu2"/>
<ref bean="stu3"/>
<ref bean="stu4"/>
</set>
</property>
Map的注入
<property name="homes">
<!-- map映射关键字 -->
<map>
<!-- map中的一个实体,以及该实体值 -->
<entry key="R1">
<!-- map中该实体的值 -->
<value>优秀班级</value>
</entry>
<!-- map中该实体的值是一个引用类型 -->
<entry key="R2“> <ref bean="stu1"/> </entry>
</map>
</property>
List及数组注入
<property name="home">
<list>
<value>黑风洞</value>
<value>花果山</value>
<value>灵山</value>
</list>
</property>
或者:
<property name="home">
<list>
<ref bean=“hello”/>
<ref bean="stu1"/>
</list>
</property>
property属性的用法
<property name="propsProperty">
<props>
<prop key="key1">bar1</prop>
<prop key="key2">bar2</prop>
</props>
</property>
Bean的实例化
就Spring IoC容器而言,bean定义基本上描述了创建一个或多个实际bean对象的内容。当需要的时候,容器会从bean定义列表中取得一个指定的bean定义,并根据bean定义里面的配置元数据使用反射机制来创建一个实际的对象。因此需要告知Spring IoC容器我们将要实例化的对象的类型以及如何实例化对象。
1、用构造器来实例化:需要指定class属性(常用);
<bean id="XXXbean" class=""/>
1、用构造器来实例化
当采用构造器来创建bean实例时,Spring对class并没有特殊的要求,我们通常使用的class都适用。也就是说,被创建的类并不需要实现任何特定的接口,或以特定的方式编码,只要指定bean的class属性即可。不过根据所采用的IoC类型,class可能需要一个默认的空构造器。
此外,IoC容器不仅限于管理JavaBean,它可以管理任意的类。不过大多数使用Spring的人喜欢使用实际的JavaBean(具有默认的(无参)构造器及setter和getter方法),但在容器中使用非bean形式(non-bean style)的类也是可以的。比如遗留系统中的连接池,很显然它与JavaBean规范不符,但Spring也能管理它。
当使用基于XML的元数据配置文件,可以这样来指定bean类:
<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>
2、使用静态工厂方法实例化
当采用静态工厂方法创建bean时,除了需要指定class属性外,还需要通过factory-method属性来指定创建bean实例的工厂方法。Spring将调用此方法(其可选参数接下来介绍)返回实例对象,就此而言,跟通过普通构造器创建类实例没什么两样。
下面的bean定义展示了如何通过工厂方法来创建bean实例。注意,此定义并未指定返回对象的类型,仅指定该类包含的工厂方法。在此例中, createInstance()必须是一个static方法
<bean id="exampleBean" class="examples.ExampleBean2" factory-method="createInstance"/>
3、使用实例工厂方法实例化
使用静态工厂方法实例化类似,用来进行实例化的实例工厂方法位于另外一个已有的bean中,容器将调用该bean的工厂方法来创建一个新的bean实例为使用此机制,class属性必须为空,而factory-bean属性必须指定为当前(或其祖先)容器中包含工厂方法的bean的名称,而该工厂bean的工厂方法本身必须通过factory-method属性来设定(参看以下的例子)。
<!-- the factory bean, which contains a method called createInstance() -->
<bean id="myFactoryBean" class="..."> ... </bean>
<!-- the bean to be created via the factory bean -->
<bean id="exampleBean" factory-bean="myFactoryBean" factory-method="createInstance"/>
虽然设置bean属性的机制仍然在这里被提及,但隐式的做法是由工厂bean自己来管理以及通过依赖注入(DI)来进行配置。
2、使用 静态工厂方法实例化:需要指定class属性外 ,还需要通过factory-method属性来指定创建bean实例的工厂方法;
<bean id="XXXbean" class="XXXfactoryClass" factory-method=""/>
3、使用实例工厂方法实例化 : class属性必须为空,而factory-bean属性必须指定为当前(或其祖先)容器中包含工厂方法的bean的名称,而该工厂bean的工厂方法本身必须通过factory-method属性来设定;
<bean id="XXXfacotry" class=""/>
<bean id="XXXbean" factory-bean="XXXfacotry" factory-method=""/>
scope属性(singleton
注:
1、在Spring中,从BeanFactory或ApplicationContext取得的实例为Singleton(单例),也就是预设为每一个Bean的别名只维持一个实例。
例如:每一次context.getBean(“helloBean”)取得的对象都是同一个,而不是每一次都产生一个新的对象。
2、使用Singleton模式产生单一实例,对单线程的程序来说并不会有什么问题,但对于多线程的程序,您必须注意到线程安全(Thread-safe)
的议题,防止多个线程同时存取共享资源所引发的数据不同步问题。
3、在Spring中,可以设定每次从BeanFactory或ApplicationContext指定别名并取得Bean时都产生一个新的实例。例如:
<bean id=“helloBean” class=“neu.danny.HelloBean” singleton=“false”>。
4、在Spring中singleton属性预设是”true”,籍由将其设定为”false”,则每次指定别名来取得Bean时都会产生一个新的实例。
5、Spring1.2的DTD继续使用“singleton”属性,但是新的Spring2.0 DTD不允许使用“singleton”属性了,改成“scope”属性来描述bean的生命周期。
scope属性(prototype
注:
Prototype(原型)作用域:
prototype作用域的Bean会导致在每次对该Bean请求(将其注入到另一个Bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的Bean实例。
根据经验,对有状态的Bean应该使用prototype作用域,而对无状态的Bean则应该使用singleton作用域。
注:
对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责:
1、容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。
2、不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法。
3、但对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。
4、清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被prototype作用域bean占用资源的一种可行方式是),通过使用bean的后置处理器,该处理器持有要被清除的bean的引用。
二、bean的作用域:在创建一个bean定义(通常为XML配置文件)时,你可以简单的将其理解为:用以创建由该bean定义所决定的实际对象实例的一张“处方(recipe)”或者模板。就如class一样,根据一张“处方”你可以创建多个对象实例。
你不仅可以控制注入到对象(bean定义)中的各种依赖和配置值,还可以控制该对象的作用域。这样你可以灵活选择所建对象的作用域,而不必在Java Class级定义作用域。
- 使用singleton,每次调用getBean()时返回相同的实例;当一个bean的作用域为singleton, 那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把一个bean定义设置为singlton作用域时,Spring IoC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都将返回被缓存的对象实例。
- 使用prototype,每次调用getBean()时返回不相同的实例;比如,在用Spring集成Struts时,我们将action的创建交给Spring来创建,就可以使用prototype,这样使得每次过来一个线程时都给你一个不同的action实例,以避免线程安全的问题。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。根据经验,对所有有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。
Spring Framework支持五种作用域(其中有三种只能用在基于web的Spring ApplicationContext)。
Bean的懒加载
<bean id="lazy" class="com.foo.ExpensiveToCreateBean" lazy-init="true">
<!-- various properties here... -->
</bean>
<bean name="not.lazy" class="com.foo.AnotherBean">
<!-- various properties here... -->
</bean>
<!-- 也可以在 beans 标签中加入“默认lazy”模式 -->
<beans default-lazy-init=“true”>
<! - - no beans will be eagerly pre-instantiated… - - >
</beans>
注:
ApplicationContext实现的默认行为就是在启动时将所有singleton bean提前进行实例化。
提前实例化意味着作为初始化过程的一部份,ApplicationContext实例会创建并配置所有的singleton bean。
然而,有时候这种默认处理可能并不是你想要的。
如果你不想让一个singleton bean在ApplicationContext实现在初始化时被提前实例化,那么可以将bean设置为延迟实例化。
一个延迟初始化bean将告诉IoC容器是在启动时还是在第一次被用到时实例化。
注:
需要说明的是,如果一个bean被设置为延迟初始化,而另一个非延迟初始化的singleton bean依赖于它,
那么当ApplicationContext提前实例化singleton bean时,
它必须确保所有上述singleton依赖bean也被预先初始化,
当然也包括设置为延迟实例化的bean。因此,如果Ioc容器在启动的时候创建了那些设置为延迟实例化的bean的实例,你也不要觉得奇怪,因为那些延迟初始化的bean可能在配置的某个地方被注入到了一个非延迟初始化singleton bean里面。
Bean的继承
<bean id="inheritedTestBean" class="org.springframework.beans.TestBean“ abstract="true" >
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="inheritsWithDifferentClass"
class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBean“ init-method="initialize">
<property name="name" value="override"/>
<!-- the age property value of 1 will be inherited from parent -->
</bean>
注:
在bean定义中包含了大量的配置信息,其中包括容器相关的信息(比如初始化方法、静态工厂方法名等等)以及构造器参数和属性值。
子bean定义就是从父bean定义继承配置数据的bean定义。
它可以覆盖父bean的一些值,或者添加一些它需要的值。
使用父/子bean定义的形式可以节省很多的输入工作。
实际上,就是一种模板形式。
Bean的初始化
1、非侵入性
<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {
public void init() {
// do some initialization work
} }
2、侵入性(不建议使用)
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements InitializingBean {
public void afterPropertiesSet() {
// do some initialization work
} }
Bean的销毁
从结果进行分析,Bean的初始化顺序应该是
1.构造函数
2.初始化属性
3.如果实现了BeanFactoryAware 接口执行setBeanFactory方法
4..如果实现了InitializingBean 接口执行afterPropertiesSet方法
5.如果在配置文件中指定了init-method,那么执行该方法
6..如果实现了BeanFactoryPostProcessor 接口在 “new”其他类之前执行 postProcessBeanFactory 方法(通过这个方法可以改变配置文件里面的属性值的配置)
7.如果实现了BeanFactoryPostProcessor 接口,那么会在其他bean初始化方法之前执行postProcessBeforeInitialization 方法,之后执行postProcessAfterInitialization方法
!感觉奇怪的地方就是没有执行destroy方法,目前还不知道原因在什么地方
如果想调用destroy方法,需要使用子类ClassPathXmlApplicationContext来声明对象;
1、非侵入性
<bean id="exampleInitBean" class="examples.ExampleBean"
destroy-method="cleanup"/>
public class ExampleBean {
public void cleanup() {
// do some destruction work (like releasing pooled connections)
} }
2、侵入性(不建议使用)
<bean id="exampleInitBean" class="examples.AnotherExampleBean"/>
public class AnotherExampleBean implements DisposableBean {
public void destroy() {
// do some destruction work (like releasing pooled connections)
} }
Bean的高级特性及其它接口
自动组装(不建议使用,代码混乱)
<bean id=“helloBean” class=“neu.danny.HelloBean“ autowire=“autodetect”/>
<property name=“hellWorld”>
<value>Hello!</value>
</property>
</bean>
依赖检查(不建议使用)
<bean id=“helloBean” class=“neu.danny.HelloBean“ autowire=byName
dependency-check=“all”/>
<property name=“hellWorld”>
<value>Hello!</value>
</property>
</bean>
1、Spring IoC容器可以自动装配(autowire)相互协作bean之间的关联关系。因此,如果可能的话,可以自动让Spring通过检查BeanFactory中的内容,来替我们指定bean的协作者(其他被依赖的bean)。由于autowire可以针对单个bean进行设置,因此可以让有些bean使用autowire,有些bean不采用。
autowire的方便之处在减少或者消除属性或构造器参数的设置,这样可以给我们的配置文件减减肥!在xml配置文件中,autowire一共有五种类型,可以在<bean/>元素中使用autowire属性指定:
注意:约定由于配置的原则,即各个bean 中属性的命名与配置文件中的id 的值要一致。还有一点就是要在配置文件的头部声明部分加入:
default-autowire=“byName”、default-autowire=“byType”
开发期间建议使用这个方式;而项目完成后稳定期,不建议使用。因为在维护升级时,我们难以查询bean之间的依赖关系。
2、 Spring除了能对容器中bean的依赖设置进行检查外。还可以检查bean定义中实际属性值的设置,当然也包括采用自动装配方式设置属性值的检查。
当需要确保bean的所有属性值(或者属性类型)被正确设置的时候,那么这个功能会非常有用。当然,在很多情况下,bean类的某些属性会具有默认值,或者有些属性并不会在所有场景下使用,因此这项功能会存在一定的局限性。就像自动装配一样,依赖检查也可以针对每一个bean进行设置。依赖检查默认为not, 它有几种不同的使用模式,在xml配置文件中,在<bean>标签使用时设定"dependency-check",可以有四种依赖检查方式:
"simple":只检查简单的属性是否完成依赖关系,像是原始数据类型或字符串对象。
"objects":设定检查对象类型的属性是否完成依赖关系
"all":检查全部的属性是否完成依赖关系
"none":设定是默认值,表示不检查依赖性。
注:
一旦使用了自动绑定时加入了依赖检查设定,如果进行依赖检查时发现有未完成的依赖关系,则执行程序时
会抛出UnsatisfiedDependencyException异常(如果没有设置依赖检查,那么只有运行到出错代码时才出错;有了依赖检查,在装载容器时就报错)
注:
Spring的依赖检查特性只对属性是否通过 setter 方法设置进行检查。 所以,即使通过构造器注入,依然会抛出异常。
autowire="autodetect"
autowire="byName"
autowire="byType"
autowire="constructor"
基于注解的配置(Annotation-Based)
<?xml version="1.0" encoding="UTF-8"?>
<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:annotation-config/>
</beans>
基于注解的配置-@autowrie
在 Spring 2.5中已经可以用注解的方式去驱动 Spring 的依赖注射了
@Autowired注解提供了与上一节中描述的同样功能,并且提供了更细致的控制与更好的适应性。
当然,要使注解可用,您必须使用 Java 5 或更新的版本,以使得可以访问源代码层次的注解。
注解可以被注册为独立 bean 的定义,但它们也可以被隐式地注册,通过基于 XML 的配置方式
@Autowired 注解可以用于“传统的”setter 方法
@Autowired注解甚至可以用于构造器与字段
因为通过类型的自动连接可能会有多个候选,因此经常需要在选择过程中加以控制。一种方法去完成这个控制就是使用@Qualifier注解
如果注入的属性允许为空@Autowired(required=false)
基于注解的配置-@Resource
javax.annotation.Resource javaee版本的通用注解可以替换autowire,
默认byName匹配
也可以与@Qualifier连用
基于注解的配置-@Component
通过组件配置的方式自动配置依赖关系
建议添加name属性
基于注解的配置-@PostConstruct@PreDestroy
初始化,销毁方法的处理
分享到:
评论

相关推荐

    springIoc实现原理

    **Spring Ioc 实现原理详解** Spring Ioc(Inversion of Control,控制反转)是Spring框架的核心特性之一,它改变了传统应用程序中对象的创建和管理方式。在传统的软件设计中,对象的创建和依赖关系的维护通常由...

    spring Ioc容器配置

    spring Ioc容器配置 IOC容器数据源配置 &lt;!-- 配置数据源 --&gt; destroy-method="close"&gt; &lt;value&gt;org.gjt.mm.mysql.Driver &lt;value&gt;jdbc:mysql://localhost:3306/demo &lt;value&gt;root ...

    spring ioc和aop原理流程图(详细)

    Spring 框架是Java开发中的核心框架,它主要由两个关键部分组成:IOC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)。这两个概念是Spring框架的核心特性,极大地简化了企业...

    实验一 Springioc基本操作.docx

    SpringIOC是Spring Framework中的核心组件之一,负责管理应用程序中的对象、依赖关系和生命周期。 在 Spring IOC 中,对象的创建和管理是通过 BeanFactory 或 ApplicationContext 实现的。BeanFactory 是 Spring ...

    spring ioc

    标题 "Spring IOC" 描述了我们讨论的核心主题——Spring 框架中的依赖注入(Inversion of Control,简称 IOC)机制。Spring 是一个广泛应用的 Java 应用开发框架,其核心特性之一就是IOC,它极大地简化了软件组件...

    Spring IoC加载流程讲解

    Spring IoC 加载流程讲解 在本节中,我们将对 Spring IoC 加载流程进行详细的讲解,并探讨 IoC 思想和依赖倒置原则的应用。 IoC 控制反转 IoC(Inversion of Control)是指在软件设计中,将对象实例的控制权从...

    SpringIoc示例代码

    Spring IOC,全称Inversion of Control,即“控制反转”,是Spring框架的核心特性之一。在传统的Java应用程序中,对象的创建和管理通常由开发者自己控制。而在Spring IOC中,这种控制权被反转,对象的创建、初始化、...

    spring ioc思维导图源文件

    Spring IOC(Inversion of Control,控制反转)是Spring框架的核心特性之一,它允许开发者将对象的创建和管理交给Spring容器来处理,从而使代码更加松耦合,更易于测试和维护。下面将详细介绍Spring IOC的基本概念、...

    SpringIOC经典Demo

    Spring IOC(Inversion of Control,控制反转)是Spring框架的核心特性,它极大地简化了Java应用的开发,通过将对象的创建和管理交由Spring容器来处理,开发者可以更专注于业务逻辑。下面,我们将深入探讨Spring IOC...

    Springioc注入Demo

    Spring IOC(Inversion of Control,控制反转)是Spring框架的核心特性,它将对象的创建和管理权交由Spring容器来负责,从而实现了依赖倒置,增强了代码的可测试性和可维护性。DI(Dependency Injection,依赖注入)...

    Spring IoC依赖包

    Spring IoC,全称为Inversion of Control,即控制反转,是Spring框架的核心特性之一。它是一种设计模式,改变了传统程序中的对象创建和管理的方式,将对象的生命周期管理交由Spring容器来负责,使得代码更加解耦,...

    Spring IOC.pdf

    Spring IOC,即Spring控制反转,是Spring框架的核心特性之一。控制反转(Inversion of Control,简称IoC)是一种设计原则,用于减少代码间的耦合,提高系统模块化和代码的重用性。在Spring框架中,IOC具体体现在对...

    Spring IoC源码深度剖析开源架构源码2021.pdf

    标题《Spring IoC源码深度剖析开源架构源码2021.pdf》和描述《Spring IoC源码深度剖析开源架构源码2021.pdf》表明该文档主要面向于分析Spring框架中控制反转(IoC)容器的核心源码,解析和理解其内部的工作机制及...

    Java反射_Spring IOC

    Java反射和Spring IOC是Java开发中的两个重要概念,它们在构建灵活、可扩展的应用程序时起着关键作用。本文将深入探讨这两个主题,并提供相关的学习资源。 首先,让我们了解一下Java反射。Java反射机制是Java语言的...

    Spring Ioc 注解 依赖注入

    ### Spring IoC与注解依赖注入详解 #### 一、Spring框架简介 Spring框架是由Rod Johnson创建的一个开源项目,最初是为了解决企业级应用开发中的复杂性问题而诞生的。Spring框架的核心特性包括IoC(Inversion of ...

    手写spring ioc(三) 资源org.zip

    在本资源"手写spring ioc(三) 资源org.zip"中,我们主要关注的是如何实现一个简易版的Spring IOC(Inversion of Control)容器,它涵盖了ioc的基本功能,包括解决循环依赖、使用构造器注入以及自动注入等核心特性。...

    模拟spring ioc过程

    在Spring框架中,IOC(Inversion of Control,控制反转)是一种设计原则,它将对象的创建和管理职责从应用代码中分离出来,交由框架来处理。这样,开发者可以更专注于业务逻辑,而不是对象的生命周期。AOP(Aspect ...

    springIOC手写框架分析

    springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC手写框架分析springIOC...

    spring ioc模块手写demo

    spring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demospring ioc模块手写demo...

    Spring IoC讲解PPT

    **Spring 的 IoC 容器** IoC(Inversion of Control)即控制反转,是 Spring 的核心特性之一。在传统的编程模式中,对象之间存在依赖关系,程序员需要手动创建和管理这些对象。而在 Spring 中,IoC 容器负责管理和...

Global site tag (gtag.js) - Google Analytics