林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka
摘要:Spring的核心容器实现了Ioc,其目 的是提供一种无侵入式的框架。在本文中,首先讲解了Spring的基础bean的相关知识,然后介绍了Spring是如何对bean进行管理的。
在Spring中,有2个最基本最重要的包,即org.springframework.beans 和org.springframework.context.在这两个包中实现了无侵入式的框架,代码中大量引用了java的反射机制,通过动态调用的方式避免了硬编码,为spring的反向控制特性提供了基础。在这2个包中,最重要的类是BeanFactory和ApplicationContext。
- BeanFactory提供了一种先进的配置机制来管理任何种类的bean。
- ApplicationContext建立在BeanFactory之上,并增加了其他功能,如国际化,获取资源,事件传递等。
一、Bean的基础知识
1.在xml配置文件中,bean的标识(id 和 name)
id:指定在benafactory中管理该bean的唯一的标识。name可用来唯一标识bean 或给bean起别名。
<bean id="helloWorld" class="com.name.HelloWorld"> ........ </bean>
2.bean的class
class属性指定了bean的来源,即bean的实际路径。注意要指定全路径,而不可只写类名。
3.Singleton的使用
在spring中,bean可被定义为2中部署模式中的一种。singleton和prototype模式。
singloeton:只有一个共享的实例存在,所有对这个bean的请求都会返回这个唯一实例。
prototype:对这个bean的每次请求都会都会创建一个新的bean实例。根据已经存在的bean而clone出来的bean。默认为singleton模式。
改写成prototype模式写法如下:
<bean id="student3" class="com.mucfc.beanfactory.Student" scope="prototype"> ....... </bean>
4.bean的属性
spring中,bean的属性值有2种注入方式。setter注入和构造函数注入。
setter注入是在调用无参的构造函数或无参的静态工厂方法实例化配置文档中定义的bean之后,通过调用bean上的setter方法实现的。
构造函数的依赖注入是通过调用带有很多参数的构造方法实现的,每个参数表示一个对象或者属性。
这里不懂看此文
5.对属性null值的处理
<bean id="student5" class="com.mucfc.beanfactory.Student"> <property name="std_name"> <value></value> </property> <property name="std_id"> <value>2005</value> </property> </bean>
或者
<bean id="student5" class="com.mucfc.beanfactory.Student"> <property name="std_name"> <value/> </property> <property name="std_id"> <value>2005</value> </property> </bean>
以上等同于this.std_name=null
6.使用依赖depends-on
此属性可在使用该bean之前,强制初始化一个或多个bean的初始化。例如
<bean id="school" class="com.mucfc.beanfactory.School" depends-on="student6"> <property name="student" ref="student6" /> </bean>
其中student6如下:
<bean id="student6" class="com.mucfc.beanfactory.Student"> <property name="std_name" value="水水" /> <property name="std_id" value="3009" /> </bean>
7.指定bean引用
<property name=" xxx" ref="yyyy "/>
或者
<property name="xxxx"> <ref bean="yyt"/> <property/>
8、ref local指定同一个xml文件中的引用
二、bean的生命周期
beanfactory中bean的生命周期图
2.1 实例bean
1.当调用者通过getBean(beanName)向容器请求某一个Bean时,如果容器注册了org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor接口,在实例化Bean之前,将调用接口的postProcessBeforeInstantiation()方法;
2.根据配置情况调用Bean构造函数或工厂方法实例化Bean;
3.如果容器注册了InstantiationAwareBeanPostProcessor接口,在实例化Bean之后,调用该接口的postProcessAfterInstantiation()方法,可在这里对已经实例化的对象进行一些"梳妆打扮";
4.如果Bean配置了属性信息,容器在这一步着手将配置值设置到Bean对应的属性中,不过在设置每个属性之前将先调用InstantiationAwareBeanPostProcessor接口的postProcessPropertyValues()方法;
2.2 初始化和使用bean
1:BeanNameAware的setBeanName():
如果Bean类有实现org.springframework.beans.BeanNameAware接口,工厂调用Bean的setBeanName()方法传递Bean的ID。
2:BeanFactoryAware的setBeanFactory():
如果Bean类有实现org.springframework.beans.factory.BeanFactoryAware接口,工厂调用setBeanFactory()方法传入工厂自身。
3:BeanPostProcessors的ProcessBeforeInitialization()
如果有org.springframework.beans.factory.config.BeanPostProcessors和Bean关联,那么其postProcessBeforeInitialization()方法将被将被调用。
4:initializingBean的afterPropertiesSet():
如果Bean类已实现org.springframework.beans.factory.InitializingBean接口,则执行他的afterProPertiesSet()方法
5:Bean定义文件中定义init-method:
可以在Bean定义文件中使用"init-method"属性设定方法名称例如:
如果有以上设置的话,则执行到这个阶段,就会执行initBean()方法
6:BeanPostProcessors的ProcessaAfterInitialization()
如果有任何的BeanPostProcessors实例与Bean实例关联,则执行BeanPostProcessors实例的ProcessaAfterInitialization()方法
BeanPostProcessor后处理器定义了两个方法:
其一是postProcessBeforeInitialization()在第8步调用;其二是Object postProcessAfterInitialization(Object bean, String beanName)方法,这个方法在此时调用,容器再次获得对Bean进行加工处理的机会;
如果在<bean>中指定Bean的作用范围为scope="prototype",将Bean返回给调用者,调用者负责Bean后续生命的管理,Spring不再管理这个Bean的生命周期。如果作用范围设置为scope="singleton",则将Bean放入到Spring IoC容器的缓存池中,并将Bean引用返回给调用者,Spring继续对这些Bean进行后续的生命管理;
2.2 销毁bean
此时,Bean已经可以被应用系统使用,并且将保留在BeanFactory中知道它不在被使用。有两种方法可以将其从BeanFactory中删除掉
1:DisposableBean的destroy()
在容器关闭时,如果Bean类有实现org.springframework.beans.factory.DisposableBean接口,则执行他的destroy()方法
2:Bean定义文件中定义destroy-method
在容器关闭时,可以在Bean定义文件中使用"destroy-method"属性设定方法名称,例如:
如果有以上设定的话,则进行至这个阶段时,就会执行destroy()方法,如果是使用ApplicationContext来生成并管理Bean的话则稍有不同,使用ApplicationContext来生成及管理Bean实例的话,在执行BeanFactoryAware的setBeanFactory()阶段后,若Bean类上有实现org.springframework.context.ApplicationContextAware接口,则执行其setApplicationContext()方法,接着才执行BeanPostProcessors的ProcessBeforeInitialization()及之后的流程。
三、Beanfactory中bean生命周期实例
下面我们来看看一个实例吧,自己新建一个工程,导入需要的Spring包,然后建立如下Worker.java(这里是bean初始化和使用时会用到的函数 )
package com.mucfc.beanlive; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; //①管理Bean生命周期的接口 public class Worker implements BeanFactoryAware,BeanNameAware,InitializingBean,DisposableBean{ private String name; private String workType; private int salary; public BeanFactory beanFactory; private String beanName; public void Worker(){ System.out.println("调用worker()构造函数"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getWorkType() { return workType; } public void setWorkType(String workType) { this.workType = workType; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } public void printInfo() { System.out.println("name:" + name + ";workType:" + workType + ";salary:" + salary); } //⑤DisposableBean接口方法 @Override public void destroy() throws Exception { System.out.println("----------------销毁bean----------------------"); System.out.println("调用DisposableBean.destroy()。"); } //④InitializingBean接口方法 @Override public void afterPropertiesSet() throws Exception { System.out.println("调用InitializingBean.afterPropertiesSet()。"); } //③BeanNameAware接口方法 @Override public void setBeanName(String arg0) { System.out.println("----------------初始化bean----------------------"); System.out.println("调用BeanNameAware.setBeanName()。"); this.beanName = arg0; } //②BeanFactoryAware接口方法 @Override public void setBeanFactory(BeanFactory arg0) throws BeansException { System.out.println("调用BeanFactoryAware.setBeanFactory()。"); this.beanFactory = arg0; } //⑥通过<bean>的init-method属性指定的初始化方法 public void myInit() { System.out.println("调用init-method所指定的myInit(),将salary设置为600。"); this.salary = 600; } //⑦通过<bean>的destroy-method属性指定的销毁方法 public void myDestroy() { System.out.println("调用destroy-method所指定的myDestroy()。"); } }
Worker类在②、③、④、⑤处实现了BeanFactoryAware、BeanNameAware、InitializingBean、DisposableBean这些Bean级的生命周期控制接口;在⑥和⑦处定义了myInit()和myDestroy()方法,以便在配置文件中通过init-method和destroy-method属性定义初始化和销毁方法。
MyInstantiationAwareBeanPostProcessor通过扩展InstantiationAwareBeanPostProcessor适配器InstantiationAwareBeanPostProcessorAdapter提供实现:
(这是实例化bean时会用到的函数)
package com.mucfc.beanlive; import java.beans.PropertyDescriptor; import org.springframework.beans.BeansException; import org.springframework.beans.PropertyValues; import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter; public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter { // ①接口方法:在实例化Bean前进行调用 public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException { System.out.println("----------------实例化bean----------------------"); // ①-1仅对容器中worker Bean进行处理 if ("worker".equals(beanName)) { System.out .println("InstantiationAware BeanPostProcessor. postProcess BeforeInstantiation"); } return null; } // ②接口方法:在实例化Bean后调用 public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException { // ②-1仅对容器中car Bean进行处理 if ("worker".equals(beanName)) { System.out .println("InstantiationAware BeanPostProcessor.postProcess AfterInstantiation"); } return true; } // ③接口方法:在设置某个属性时调用 public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { // ③-1仅对容器中wroker Bean进行处理,还可以通过pdst入参进行过滤, // 仅对car的某个特定属性时进行处理。 if ("worker".equals(beanName)) { System.out .println("Instantiation AwareBeanPostProcessor.postProcess PropertyValues"); } return pvs; } }
在MyInstantiationAwareBeanPostProcessor中,我们通过过滤条件仅对work Bean进行处理,而对其他的Bean一概视而不见。
此外,我们还提供了一个BeanPostProcessor实现类,在该实现类中,我们也只对work Bean进行处理,对配置文件所提供的属性设置值进行判断,并执行相应的"补缺补漏"的操作:
BeanPostProcessor实现类(这里是bean初始化和使用时会用到的函数 )
package com.mucfc.beanlive; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class MyBeanPostProcessor implements BeanPostProcessor{ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if(beanName.equals("worker")){ Worker worker = (Worker)bean; if(worker.getWorkType() == null){ System.out.println("调用BeanPostProcessor.postProcess AfterInitialization(), getWorkType为空,设置为默认临时工"); worker.setWorkType("临时工"); } } return bean; } @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if(beanName.equals("worker")){ Worker worker = (Worker)bean; if(worker.getSalary() >= 1000){ System.out.println("调用BeanPostProcessor.postProcess BeforeInitialization(), 将salary调整为800。"); worker.setSalary(800); } } return bean; } }
在MyBeanPostProcessor类的postProcessBeforeInitialization()方法中,我们首先判断处理的Bean是否名为worker,如果是,进一步判断该Bean的workerType属性是否为空,如果为空,将该属性设置为"临时工"。在postProcessAfterInitialization()方法中,我们也是只对名为woker的Bean进行处理,判断其salary是否超过最大速度1000,如果超过,将其设置为800。(黑心老板啊!!!!!)
至于如何将MyInstantiationAwareBeanPostProcessor和MyBeanPostProcessor这两个后处理器注册到BeanFactory容器中
现在,我们在Spring配置文件中定义Car的配置信息,如代码清单3 29所示:
然后就是beans.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" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <bean id="worker" class="com.mucfc.beanlive.Worker" init-method="myInit" destroy-method="myDestroy" p:name="小强" p:salary="1000" /> </beans>
使用方法:
package com.mucfc.beanlive; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.xml.XmlBeanFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; public class Test { private static void LifeCycleInBeanFactory(){ //①下面两句装载配置文件并启动容器 Resource res = new ClassPathResource("beans.xml"); BeanFactory bf = new XmlBeanFactory(res); //②向容器中注册MyBeanPostProcessor后处理器 ((ConfigurableBeanFactory)bf).addBeanPostProcessor(new MyBeanPostProcessor()); //③向容器中注册MyInstantiationAwareBeanPostProcessor后处理器 ((ConfigurableBeanFactory)bf).addBeanPostProcessor( new MyInstantiationAwareBeanPostProcessor()); //④第一次从容器中获取worker,将触发容器实例化该Bean,这将引发Bean生命周期方法的调用。 Worker worker1 = (Worker)bf.getBean("worker"); System.out.println("第一次从容器中获取worker"); worker1.printInfo(); System.out.println("修改第一次从容器中获取worker的workType"); worker1.setWorkType("正式工"); System.out.println("第一次从容器中获取worker(修改过后的)"); worker1.printInfo(); //⑤第二次从容器中获取worker,直接从缓存池中获取 System.out.println("第二次从容器中获取worker"); Worker worker2= (Worker)bf.getBean("worker"); worker2.printInfo(); //⑥查看worker1和worker2是否指向同一引用 System.out.println("查看worker1和worker2是否指向同一引用 "); System.out.println("worker1==worker2:"+(worker1==worker2)); //⑦关闭容器 ((XmlBeanFactory)bf).destroySingletons(); } public static void main(String[] args) { LifeCycleInBeanFactory(); } }
输出结果:
图片看不清的话,看文字吧:
四月 07, 2015 3:43:54 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [beans.xml]
----------------实例化bean----------------------
InstantiationAware BeanPostProcessor. postProcess BeforeInstantiation
InstantiationAware BeanPostProcessor.postProcess AfterInstantiation
Instantiation AwareBeanPostProcessor.postProcess PropertyValues
----------------初始化bean----------------------
调用BeanNameAware.setBeanName()。
调用BeanFactoryAware.setBeanFactory()。
调用BeanPostProcessor.postProcess BeforeInitialization(), 将salary调整为800。
调用InitializingBean.afterPropertiesSet()。
调用init-method所指定的myInit(),将salary设置为600。
调用BeanPostProcessor.postProcess AfterInitialization(), getWorkType为空,设置为默认临时工
第一次从容器中获取worker
name:小强;workType:临时工;salary:600
修改第一次从容器中获取worker的workType
第一次从容器中获取worker(修改过后的)
name:小强;workType:正式工;salary:600
第二次从容器中获取worker
name:小强;workType:正式工;salary:600
查看worker1和worker2是否指向同一引用
worker1==worker2:true
四月 07, 2015 3:43:54 下午 org.springframework.beans.factory.xml.XmlBeanFactory destroySingletons
信息: Destroying singletons in [email protected]: defining beans [worker]; root of factory hierarchy
----------------销毁bean----------------------
调用DisposableBean.destroy()。
调用destroy-method所指定的myDestroy()。
我们可以看到第二次获取worker时,直接从容器的缓存中获取,它们两个的指向的是同一个引用!切记!
四、ApplicationContext与beanfactory的区别
从ApplicationContext应用上下文容器中获取bean和从bean工厂容器中获取bean的区别?
具体案例:
1、从ApplicationContext中获取bean
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
当我们去实例化beans.xml,该文件中配置的bean被实例化,(该bean的scope是singleton(单例))
2、如果我们使用beanfactory去获取bean,当你只是实例化该容器,那么容器的bean不被实例化,只有当你去使用getBean某个bean是,才会实时的创建
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
factory.getBean("student");
结论:
1、如果使用ApplicationContext,则配置的bean如果是singleton(单例)不管你用不用都被实例化,好处就是可以预先加载,坏处是浪费内存,
2、如果是用BeanFactory,则当你实例化该对象的时候,配置的bean不会被马上实例化,当你使用的时候才会被实例化(就像延缓加载机制)好处就是节约内存,缺点是速度回降慢,
3规则:一般没有特殊的要求,应当使用ApplicationContext完成(90%以上的项目)
使用ApplicationContext三种经常用到的实现:
1、ClassPathXmlApplicationContext->从类路径加载
2、FileSystemXmlApplicationContext->从文件系统加载
举例:ApplicationContext ac = newFIleSystemXmlApplicationContext("C:\Users\Workspaces\MyEclipse
8.5\myspring\src\com\zqx\inter\beans.xml");
3、XmlWebApplicationContext->从web系统中加载(当tomcat启动的时候加载)
林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka