一、动态工厂Bean
创建一个Factory类来作为获取对象的方式:
public class MyService {
public void doSomething() {
System.out.println("我是MyService中doSomething....");
}
}
public class MyFactory {
public MyService getService() {
return new MyService();
}
}
@org.junit.Test
public void test1() {
MyFactory factory = new MyFactory();
MyService service = factory.getService();
service.doSomething();
}
这样的方式不仅将MyFactory耦合到了测试代码中,还将MyService也耦合到了测试代码中。这将导致代码难以维护。
在spring中可以采用动态工厂Bean的方式,将代码从耦合的状态解救出来,applicationContext.xml配置文件如下:
然后就可以像获取普通的Bean方式一样来获取又工厂创建的Bean了:
@org.junit.Test
public void test2() {
String config = "cn/lwb/spring/BeanAutoAssemble/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(config);
MyService myService = (MyService)applicationContext.getBean("myService");
myService.doSomething();
}
二、静态工厂Bean
静态工厂类就是将上面工厂类中获取service的方法改为static方法:
public class MyFactory {
public static MyService getService() {
return new MyService();
}
}
配置文件中的配置就因该按照如下来配置:
在上面的这个配置中,如果没有factory-method属相,那么myService就是表示的工厂Bean,但是加上这个factory-method属性,这个配置表示的意思就变了,表示由某个类的某个方法创建了某个对象。
三、容器中 Bean 的作用域
在Spring中,ApplicationContext容器在初始化的时候,就创建了定义的bean,那么在如下的代码中:
public class MyService {
public MyService() {
System.out.println("我是构造放方法....");
}
public void doSomething() {
System.out.println("我是MyService中doSomething....");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="service" class="cn.lwb.spring.scope.MyService"></bean>
</beans>
@org.junit.Test
public void test1() {
String config = "cn/lwb/spring/scope/applicationContext.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(config);
MyService service1 = (MyService)applicationContext.getBean("service");
MyService service2 = (MyService)applicationContext.getBean("service");
System.out.println(service1 == service2);
}
在测试中输出的结果为true,说明我们得到的service1和service2是同一个对象,并且MyService的构造方法只调用了一次。
如果将配置文件改为如下的模式:
再次调用,会发现结果为false,并且构造方法运行了两次。其实scope的默认参数是singleton(单例)而prototype(多例)
总结:spring中Bean的作用域有5种
scope=“prototype”:在容器初始化的时候创建,是默认值(单例模式)。
scope=“prototype”:在容器初始化的时候不创建,而是在真正使用的时候创建(原型模式、多例模式)。
scope=“request”:对于每次 HTTP 请求,都将会产生一个不同的 Bean 实例
scope=“session”:对于每个不同的 HTTP session,都将产生一个不同的 Bean 实例
scope=“global session”:每个全局的 HTTP session 对应一个 Bean 实例。典型情况下,仅在使用
portlet 集群时有效,多个 Web 应用共享一个 session。一般应用中, global-session 与 session
是等同的。
注意:
(1)对于 scope 的值 request、 session 与 global session, 只有在 Web 应用中使用 Spring 时,
该作用域才有效。
(2)对于 scope 为 singleton 的单例模式, 该 Bean 是在容器被创建时即被装配好了。
(3)对于 scope 为 prototype 的原型模式, Bean 实例是在代码中使用该 Bean 实例时才进行
装配的。
Bean的生命周期
Step1:调用无参构造器,创建实例对象。
Step2:调用参数的 setter,为属性注入值。
Step3:若 Bean 实现了 BeanNameAware 接口,则会执行接口方法 setBeanName(String beanId),使 Bean 类可以获取其在容器中的 id 名称。
Step4:若 Bean 实现了 BeanFactoryAware 接口,则执行接口方法 setBeanFactory(BeanFactoryfactory),使 Bean 类可以获取到 BeanFactory 对象。
Step5 :若 定 义 并 注 册 了 Bean 后 处 理 器 BeanPostProcessor , 则 执 行 接 口 方 法postProcessBeforeInitialization()。
Step6:若 Bean 实现了 InitializingBean 接口,则执行接口方法 afterPropertiesSet ()。 该方法在 Bean 的所有属性的 set 方法执行完毕后 执行,是 Bean 初始化结束的标志,即 Bean 实例化结束。
Step7:若设置了 init-method 方法,则执行。
Step8 : 若 定 义 并 注 册 了 Bean 后 处 理 器 BeanPostProcessor , 则 执 行 接 口 方 法postProcessAfterInitialization()。
Step9:执行业务方法。
Step10:若 Bean 实现了 DisposableBean 接口,则执行接口方法 destroy()。
Step11:若设置了 destroy-method 方法,则执行。