一、lazy-init
lazy-init是延迟初始化的意思。
spring中容器都是尽早的创建和配置所有的单例bean,因此当容器在启动时,就会去配置和创建单例bean。
这样做的好处是在程序刚运行时就可以将配置的错误或者环境问题立刻暴露出来。当然,坏处就是启动时,因为要初始化所有的单例bean,系统开销会很大,启动过程比较慢。
如果不想单例bean提前实例化,可以设置lazy-initialized延迟加载,只有在第一次请求的时候采取初始化,而不是在启动容器时初始化。
在XML中,属性lazy-init控制元素的初始化。
<bean id="order" class="twm.spring.start.Order" lazy-init="true"/>
<bean name="customer" class="twm.spring.start.Customer"/>
ApplicationContext加载上面的配置启动时,customer会预先初始化,而order则不会。
如果一个非延迟的单例bean依赖了标记了lazy-init的bean,那么这个标记了lazy-init的bean也会在容器启动时被创建(延迟初始化失效)。
设置为延迟加载的bean一旦注入给不延迟的单例bean,就意味着它并不会被延迟加载了。
<bean id="notify" class="twm.spring.start.NotifyServiceByCellPhoneImpl" lazy-init="true" />
<bean id="order" class="twm.spring.start.Order">
<constructor-arg name="notifyservice" ref="notify" />
</bean>
例如这个例子,notify bean虽然设置了延迟加载,但由于它需要注入到order bean(没有设置延迟加载),因此notify bean并不会延迟加载了。
通过设置元素的default-lazy-init属性,可以设置容器级别的延迟加载。看样例:
如果是通过Java代码初始化bean则需要实现Lazy接口重写value方法即可
class MyBean implements Lazy{
@Override
public boolean value() {
return true;
}
}
二、depends-on
思考一个问题:有两个类并没有依赖注入的关系,但是初始化过程却有先后顺序关系。
比如read bean初始化时需要读取配置,write bean初始化时会写入配置。那么read bean只能在write bean之后初始化。
创建一个类MockFile.java,里面放一个静态变量,用来模拟文件存储:
public class MockFile {
private static String filecontent;
public static String getFilecontent() {
return filecontent;
}
public static void setFilecontent(String filecontent) {
MockFile.filecontent = filecontent;
}
}
创建ReadWork.java:
public class ReadWork {
public ReadWork() {
System.out.print("ReadWork构造函数初始化,读取模拟文件内容:");
System.out.println(MockFile.getFilecontent());
}
}
创建WriteWork.java:
public WriteWork() throws InterruptedException {
System.out.println("WriteWork构造函数初始化,并向模拟文件写入内容:property:better");
Thread.sleep(3000);
MockFile.setFilecontent("property:better");
}
在容器配置文件beans.xml中注册对象:
<bean id="writeWork" class="twm.spring.depends.WriteWork" />
<bean id="readWork" class="twm.spring.depends.ReadWork" />
启动触发容器初始化:
public static void main(String[] args) throws Exception {
new ClassPathXmlApplicationContext("beans.xml");
}
运行程序:
首先会输出:
WriteWork 构造函数初始化,并向模拟文件写入内容:property:better
3秒钟后会输出:
ReadWork 构造函数初始化,读取模拟文件内容:property:better
由此可知,容器会按配置文件中的先后顺序初始化对象bean,并且初始过程非并发执行的。
现在来给writeWork bean加上延迟加载属性:
<bean id="writeWork" class="twm.spring.depends.WriteWork" lazy-init="true" />
再运行程序,只会输出:
ReadWork 构造函数初始化,读取模拟文件内容:null
因为writeWork bean加上延迟加载属性,而程序中又没有请求调用writeWork bean 的地方,所以writeWork bean不会被实例化。
因此模拟文件不会被写入内容。
我想让write bean在read bean之前初始化,怎么办呢?
在readWork上加上depends-on属性就可以了:
<bean id="readWork" class="twm.spring.depends.ReadWork" depends-on="writeWork" />
这是告诉容器readWork的初始化,依赖于writeWork,所以你必须让writeWork先初始化。
也可以依赖多个bean,为depends-on属性值列表可用逗号,空白,分号分隔。
<bean id="readWork" class="twm.spring.depends.ReadWork" depends-on="writeWork,logger,dbconnect" />
如果是通过Java代码的方式初始化则需要实现DepondsOn接口
class MyBean implements DependsOn {
@Override
public String[] value() {
return new String[beanname...];
}
}