[跟我学spring学习笔记][更多DI知识]
延迟初始化Bean
定义:
延迟初始化也叫做惰性初始化,指不提前初始化Bean,在真正使用时才创建并初始化Bean
如何延迟:
配置方式很简单只需在标签上指定 “lazy-init” 属性值为“true”即可延迟初始化Bean。
默认为什么为不延迟或者说什么时候要延迟?:
Spring容器预先初始化Bean通常能帮助我们提前发现配置错误,所以如果没有什么情况建议开启,除非有某个Bean可能需要加载很大资源,而且很可能在整个应用程序生命周期中很可能使用不到,可以设置为延迟初始化。
配置例子如下:
<bean id="helloApi" class="cn.javass.spring.chapter2.helloworld.HelloImpl" lazy-init="true"/>
使用depends-on//以及了解init,destory
注意回销回调
什么是depens-on?:
depends-on是指指定Bean初始化及销毁时的顺序,使用depends-on属性指定的Bean要先初始化完毕后才初始化当前Bean,由于只有“singleton”Bean能被Spring管理销毁,所以当Bean都是“singleton”时,使用depends-on属性指定的Bean要在Bean之后销毁。
配置例子:
<bean id="helloApi" class="cn.javass.spring.chapter2.helloworld.HelloImpl"/> <bean id="decorator" class="cn.javass.spring.chapter3.bean.HelloApiDecorator" depends-on="helloApi"> <property name="helloApi"><ref bean="helloApi"/></property> </bean>
用法:
“decorator”指定了“depends-on”属性为“helloApi”,所以在“decorator”Bean初始化之前要先初始化“helloApi”,而在销毁“helloApi”之前先要销毁“decorator”,大家注意一下销毁顺序,与文档上的不符。
“depends-on”属性可以指定多个Bean,若指定多个Bean可以用“;”、“,”、空格分割。
优点:
那“depends-on”有什么好处呢?主要是给出明确的初始化及销毁顺序,比如要初始化“decorator”时要确保“helloApi”Bean的资源准备好了(有可能仅靠Bean的初始化是不够的,比如文件没有打开好,你就操作文件了),否则使用“decorator”时会看不到准备的资源;而在销毁时要先在“decorator”Bean的把对“helloApi”资源的引用释放掉才能销毁“helloApi”,否则可能销毁 “helloApi”时而“decorator”还保持着资源访问,造成资源不能释放或释放错误。
例子:
在平常开发中我们可能需要访问文件系统,而文件打开、关闭是必须配对的,不能打开后不关闭,从而造成其他程序不能访问该文件。让我们来看具体配置吧:
1)准备测试类:
ResourceBean从配置文件中配置文件位置,然后定义初始化方法init中打开指定的文件,然后获取文件流;最后定义销毁方法destroy用于在应用程序关闭时调用该方法关闭掉文件流。
DependentBean中会注入ResourceBean,并从ResourceBean中获取文件流写入内容;定义初始化方法init用来定义一些初始化操作并向文件中输出文件头信息;最后定义销毁方法用于在关闭应用程序时想文件中输出文件尾信息。
2) 配置文件
<bean id="resourceBean" class="cn.javass.spring.chapter2.helloworld.ResourceBean" init-method="init" destroy-method="destory"> <property name="file" value="test.txt"/> </bean> <bean id="dependentBean" class="cn.javass.spring.chapter2.helloworld.DependentBean" init-method="init" destroy-method="destory" depends-on="resourceBean"> <property name="resourceBean" ref="resourceBean"/> </bean>
- \配置:Spring容器能自动把字符串转换为java.io.File。
- init-method=”init” :指定初始化方法,在构造器注入和setter注入完毕后执行。
- destroy-method=”destroy”:指定销毁方法,只有“singleton”作用域能销毁,“prototype”作用域的一定不能,其他作用域不一定能;后边再介绍。
Java代码
package cn.javass.spring.chapter3; import java.io.IOException; import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; import cn.javass.spring.chapter3.bean.DependentBean; public class MoreDependencyInjectTest { @Test public void testDependOn() throws IOException { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("chapter3/depends-on.xml"); //一点要注册销毁回调,否则我们定义的销毁方法不执行 context.registerShutdownHook(); DependentBean dependentBean = context.getBean("dependentBean", DependentBean.class); dependentBean.write("aaa"); } }
自动装配
定义
自动装配就是指由Spring
来自动地注入依赖对象,无需人工参与。
目前有4种自动装配的方式:
- no 默认
- byName
- byType
- constr uctor
其中Spring3.0已不推荐使用之前版本的“autodetect
”自动装配,推荐使用Java 5+支持的(@Autowired
)注解方式代替
好处:
自动装配的好处是减少构造器注入和setter注入配置,减少配置文件的长度。自动装配通过配置标签的“autowire”属性来改变自动装配方式
配置的含义:
-
default
:使用默认的自动装配,默认的自动装配需要在标签使用default-autowire属性指定. -
no
:意思是不支持自动装配,指明依赖 -
byName
:通过设置autowire=”byName’,意思是根据名字进行自动装配,只能用于setter注入.能替换property.比如我们有方法“setHelloApi”,则“byName”方式Spring容器将查找名字为helloApi的Bean并注入,如果找不到指定的Bean,将什么也不注入。
-
byType
通过设置Bean定义属性autowire=”byType”,意思是指根据类型注入,用于setter注入比如如果指定自动装配方式为“byType”,而“setHelloApi”方法需要注入HelloApi类型数据,则Spring容器将查找HelloApi类型数据,如果找到一个则注入该Bean,如果找不到将什么也不注入,如果找到多个Bean将优先注入标签“
primary
”属性为true
的Bean,否则抛出异常来表明有个多个Bean发现但不知道使用哪个tips:
根 据类型找到多个Bean时,对于集合类型(如List、Set)将注入所有匹配的候选者,而对于其他类型遇到这种情况可能需要使用“autowire- candidate”属性为false来让指定的Bean放弃作为自动装配的候选者,或使用“primary”属性为true来指定某个Bean为首选 Bean
-
constructor
:通过设置Bean定义属性autowire=”constructor”,功能和“byType”功能一样,根据类型注入构造器参数,只是用于构造器注入方式.-
autodetect
: 已不使用
不是所有类型都能自动装配
略
自动装配注入方式能和配置注入方式一同工作吗?当然可以,大家只需记住配置注入的数据会覆盖自动装配注入的数据。
不建议采用自动装配
自动装配也是有缺点的,最重要的缺点就是没有了配置,在查找注入错误时非常麻烦,还有比如基本类型没法完成自动装配,所以可能经常发生一些莫名其妙的错误,在此我推荐大家不要使用该方式,最好是指定明确的注入方式,或者采用最新的Java5+注解注入方式。所以大家在使用自动装配时应该考虑自己负责项目的复杂度来进行衡量是否选择自动装配方式。
依赖检查
定义:
上一节介绍的自动装配,很可能发生没有匹配的Bean进行自动装配,如果此种情况发生,只有在程序运行过程中发生了空指针异常才能发现错误,如果能提前发现该多好啊,这就是依赖检查的作用。
依赖检查:用于检查Bean定义的属性都注入数据了,不管是自动装配的还是配置方式注入的都能检查,如果没有注入数据将报错,从而提前发现注入错误,只检查具有setter方法的属性。
Spring3+也不推荐配置方式依赖检查了,建议采用Java5+ @Required注解方式,测试时请将XML schema降低为2.5版本的,和自动装配中“autodetect”配置方式的xsd一样。
不推荐 :也懒得仔细学了
方法注入(看不懂)
所谓方法注入其实就是通过配置方式覆盖或拦截指定的方法,通常通过代理模式实现。Spring提供两种方法注入:查找方法注入和方法替换注入。
因为Spring是通过CGLIB动态代理方式实现方法注入,也就是通过动态修改类的字节码来实现的,本质就是生成需方法注入的类的子类方式实现。
在进行测试之前,我们需要确保将“ccm.springsource.cn.sf.cglib-2.2.0.jar”放到lib里并添加到“Java Build Path”中的Libararies中。否则报错,异常中包含“nested exception is java.lang.NoClassDefFoundError: cn/sf/cglib/proxy/CallbackFilter”。
查找方法注入
一、查找方法注入:又称为Lookup方法注入,用于注入方法返回结果,也就是说能通过配置方式替换方法返回结果。使用配置;其中name属性指定方法名,bean属性指定方法需返回的Bean。
方法定义格式:访问级别必须是public或protected,保证能被子类重载,可以是抽象方法,必须有返回值,必须是无参数方法,查找方法的类和被重载的方法必须为非final:
替换方法注入
二、替换方法注入:也叫“MethodReplacer”注入,和查找注入方法不一样的是,他主要用来替换方法体。通过首先定义一个MethodReplacer接口实现,然后如下配置来实现: