02_Spring IOC(控制反转)
2018-01-20 本文已影响0人
小窗风雨
IOC的概念
- IOC Inversion of Controller 控制反转。
- IOC 就是将对象的创建、初始化及销毁交给 spring 容器来处理。
ApplicationContext 与 BeanFactory 的关系
- ApplicationContext 是 BeanFactory 的子接口。
- BeanFactory 采用延迟加载的方案,在getBean时才会实例化Bean。
- XmlBeanFactory
public void test4() { BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml")); beanFactory.getBean("helloWorld"); } // 经过测试,BeanFactory在getBean时才实例化Bean。
- ApplicationContext 在配置文件加载时,就会初始化Bean,并且提供不同应用层的实现。在开发中我们一般使用 ApplicationContext 的实现类:
- FileSystemXmlApplicationContext 根据文件路径读取xml文件
public void test5() { // 根据系统文件路径读取xml文件 ApplicationContext context = new FileSystemXmlApplicationContext("src/applicationContext.xml"); context.getBean("helloWorld"); }
- ClassPathXmlApplicationContext 根据classpath路径读取xml文件
public void test5() { // 根据classpath路径读取xml文件 ApplicationContext context = new FileSystemXmlApplicationContext("applicationContext.xml"); context.getBean("helloWorld"); }
- WebApplicationContext web开发中常用
Bean的实例化方式
- 无参构造方法
- 编写配置文件
applicationContext.xml
<?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="helloWorld" class="com.zhangquanli.spring.helloworld.HelloWorld"/> </beans>
- 编写测试方法
public void test1() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld"); helloWorld.show(); }
- 编写配置文件
- 静态工厂方法
- 编写工厂类,在工厂类中提供一个静态方法,返回Bean对象
public class HelloWorldFactory { public static HelloWorld getInstance() { return new HelloWorld(); } }
- 编写配置文件
applicationContext.xml
<?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="helloWorld2" class="com.zhangquanli.spring.helloworld.HelloWorldFactory" factory-method="getInstance"/> </beans>
- 编写测试方法
public void test2() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld2"); helloWorld.show(); }
- 实例工厂方法
- 编写工厂类,在工厂类中提供一个非静态方法,返回Bean对象
public class HelloWorldFactory2 { public HelloWorld getInstance() { return new HelloWorld(); } }
- 编写配置文件
applicationContext.xml
<?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="helloWorldFactory2" class="com.zhangquanli.spring.helloworld.HelloWorldFactory2"/> <bean id="helloWorld3" factory-bean="helloWorldFactory2" factory-method="getInstance"/> </beans>
- 编写测试方法
public void test3() { ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld3"); helloWorld.show(); }
Bean的别名
- 编写配置文件
<?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="helloWorld" class="com.zhangquanli.spring.helloworld.HelloWorld"/>
<alias name="helloWorld" alias="a"/>
<alias name="helloWorld" alias="b"/>
<alias name="helloWorld" alias="c"/>
</beans>
- 编写测试方法
public void testAlias() {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloWorld a = (HelloWorld) context.getBean("a");
a.show();
HelloWorld b = (HelloWorld) context.getBean("b");
b.show();
HelloWorld c = (HelloWorld) context.getBean("c");
c.show();
}
Bean的创建时机
- 在 bean 标签中有 lazy-init 属性
- default,相当于 false,在 spring 容器启动的时候创建对象。
- true,在 context.getBean 时创建对象。
- false,在 spring 容器启动的时候创建对象。
- lazy-init 属性的意义
- 如果把 lazy-init 设置为 true ,则当 spring 容器启动的时候,检测不到任何错误,这样会存在很大的安全性隐患。所以一般情况应该设置 lazy-init 为 false/default 。
- 但是如果一个bean中有一个属性,该属性含有大量的数据,这个时候不希望该bean过早的停留在内存中,这个时候需要用到 lazy-int 为 true 。
Bean的作用域
- 在 bean 标签中有 scope 属性,用于描述 bean 的作用域。
- singleton,单例模式,代表在 spring ioc 容器中只有一个 bean 实例。(默认的scope)
- prototype,多例模式,每一次从 spring ioc 容器中获取,都会返回一个新实例。
- request,用在web开发中,通过 request.setAttribute() 将 bean 对象存储到request域中。
- session,用在web开发中,通过 session.setAttribute() 将 Bean 对象存储到session域中。
- 默认情况下,放入spring容器中的bean是单例的。
- 将来service层和dao层所有的类将放入到spring容器中,所以默认情况下这两个层的类的实例都是单例的,所以不能把数据声明到属性中。如果声明到属性中,将会成为共享的,涉及到线程安全问题。
创建时机和作用域的结合
- <font color="red">
scope="prototype" lazy-init="true"
</font> 在 context.getBean 时创建对象 - <font color="red">
scope="prototype" lazy-init="false"
</font> 在 context.getBean 时创建对象,lazy-init为false失效。即在 scope 为 prototype 时,始终在 context.getBean 时创建对象 - scope为singleton时,是默认情况。
Bean的生命周期
- Bean的生命周期方法
- instantiate bean 实例化 Bean 对象
- populate properties 给 Bean 对象注入属性
- 如果 Bean 实现 BeanNameAware 执行 setBeanName
- 如果 Bean 实现 BeanFactoryAware 或 ApplicationContextAware 执行 setBeanFactory 或 setApplicationContext
- 如果存在类实现 BeanPostProcessor 执行postProcessBeforeInitialization
- 如果 Bean 实现 InitializingBean 执行 afterPropertiesSet
- 调用 Bean 中自定义的 init-method 方法
- 如果存在类实现 BeanPostProcessor 执行postProcessorAfterInitialization
- 执行业务逻辑代码
- 如果 Bean 实现 DisposableBean 执行 destroy
- 调用 Bean 中自定义的 destroy-method 方法
- Bean的生命周期测试代码
- HelloWorld.java
import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class HelloWorld implements BeanNameAware,ApplicationContextAware,InitializingBean,DisposableBean { private String info; public String getInfo() { return info; } public void setInfo(String info) { this.info = info; } public HelloWorld() { System.out.println("第一步:instantiate bean 实例化Bean对象"); } public void show() { System.out.println("第九步:show time 执行业务逻辑代码"); } public void myInit() { System.out.println("第七步:调用 Bean 中自定义的 init-method 方法"); } public void myDestroy() { System.out.println("第十一步:调用 Bean 中自定义的 destroy-method 方法"); } @Override public void setBeanName(String arg0) { System.out.println("第三步:如果 Bean 实现 BeanNameAware 执行 setBeanName" + info); } @Override public void setApplicationContext(ApplicationContext arg0) throws BeansException { System.out.println("第四步:如果 Bean 实现 BeanFactoryAware 或 ApplicationContextAware 执行 setBeanFactory 或 setApplicationContext"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("第六步:如果 Bean 实现 InitializingBean 执行 afterPropertiesSet"); } @Override public void destroy() throws Exception { System.out.println("第十步:如果 Bean 实现 DisposableBean 执行 destroy"); } }
- MyProcessor.java
import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyProcessor implements BeanPostProcessor{ @Override public Object postProcessAfterInitialization(Object arg0, String arg1) throws BeansException { System.out.println("第八步:如果存在类实现 BeanPostProcessor 执行postProcessorAfterInitialization"); return arg0; } @Override public Object postProcessBeforeInitialization(Object arg0, String arg1) throws BeansException { System.out.println("第五步:如果存在类实现 BeanPostProcessor 执行postProcessBeforeInitialization"); return arg0; } }
- applicationContext.xml
<?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="helloWorld" class="com.zhangquanli.spring.life.HelloWorld" init-method="myInit" destroy-method="myDestroy"> <property name="info" value="你好啊"></property> </bean> <!-- 此类是针对所有其他bean类的 --> <bean id="myProcessor" class="com.zhangquanli.spring.life.MyProcessor"/> </beans>
- HelloWorldTest
import org.junit.Test; import org.springframework.context.support.ClassPathXmlApplicationContext; public class HelloWorldTest { @Test public void test1() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld"); helloWorld.show(); context.close(); } }
- Bean的生命周期的说明
- 第3步和第4步,是让 Bean 了解 spring 容器。
- 第5步和第8步,可以针对指定 的Bean 使用动态代理进行功能增强。
- 第6步和第10步,可以实现指定的接口来完成 init 和 destroy 操作。
- 在开发中,一般不使用第6步和第10步,因为第7步和第11步也可以完成 init 和 destroy 的操作。同时,第7步和第11步的初始化和销毁操作无耦合,只需要在配置文件制定初始化和销毁的方法。
<bean id="helloWorld" class="com.zhangquanli.spring.life.HelloWorld" init-method="myInit" destroy-method="myDestroy"> <property name="info" value="你好啊"></property> </bean>
- Bean的生命周期的总结
- 增强 Bean 的功能,可以实现 BeanPostProcessor 来完成。
- 初始化和销毁操作,可以使用 bean 标签上的 init-method、destroy-method 方法来完成。
- <font color="red">注意:destroy-method 只在 scope="singleton" 才有效果。</font>