spring的bean
2015-08-07 20:09
816 查看
1.spring管理bean的原理
spring是如何帮我们创建和管理bean的呢?首先读取配置文件获取bean对象。可以通过dom4j来读取配置文件,获取文档下所有bean节点,bean节点的id和class的属性值构造出bean对象,将所有bean对象装到一个List集合中。
然后完成bean的实例化,将bean节点的id属性作为key,bean对象作为值,存到map中。
最后我们就可以通过map获取bean实例了。
具体代码如下所示:
package junit.test; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.XPath; import org.dom4j.io.SAXReader; /** * 传智博客版容器 * @author Lee * */ public class ItcastClassPathXMLApplicationContext { private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>(); private Map<String, Object> sigletons = new HashMap<String, Object>(); /** * * @param filename 指定配置文件的名称 */ public ItcastClassPathXMLApplicationContext(String filename) { this.readXML(filename); this.instanceBeans(); } /** * 完成Baen的实例化 */ private void instanceBeans() { for(BeanDefinition beanDefinition : beanDefines){ try { if(beanDefinition.getClassName() != null && !"".equals(beanDefinition.getClassName())); sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance()); } catch (Exception e) { e.printStackTrace(); } } } /** * 使用dom4j读取spring配置文件 * @param filename */ private void readXML(String filename) { SAXReader saxReader = new SAXReader(); Document document = null; try { URL xmlpath = this.getClass().getClassLoader().getResource(filename); document = saxReader.read(xmlpath); Map<String, String> nsMap = new HashMap<String, String>(); nsMap.put("ns","http://www.springframework.org/schema/beans"); //加入命名空间 XPath xsub = document.createXPath("//ns:beans/ns:bean"); // 创建beans/bean查询路径 xsub.setNamespaceURIs(nsMap); // 设置命名空间 @SuppressWarnings("unchecked") List<Element> beans = xsub.selectNodes(document); // 获取文档下所有bean节点 for(Element element : beans){ String id = element.attributeValue("id"); // 获取id属性值 String clazz = element.attributeValue("class"); // 获取class属性值 BeanDefinition beanDefine = new BeanDefinition(id, clazz); beanDefines.add(beanDefine); } } catch (Exception e) { e.printStackTrace(); } } /** * 获取Bean实例 * @param beanName * @return */ public Object getBean(String beanName) { return this.sigletons.get(beanName); } }
2.spring的三种实例化bean的方式
1.使用类构造器实例化<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"/>
2.使用静态工厂方法实例化
在工厂类里面有一个静态工厂方法,这个静态工厂方法专门用于创建bean对象的。在配置文件bean节点里面,class指定的就是工厂类,由factory-method制定静态工厂方法。
<bean id="personService2" class="cn.itcast.service.impl.PersonServiceBeanFactory" factory-method="createPersonServiceBean"/>
package cn.itcast.service.impl; public class PersonServiceBeanFactory { public static PersonServiceBean createPersonServiceBean() { return new PersonServiceBean(); } }3.使用实例工厂方法实例化
在配置文件里面,先实例化工厂,然后使用工厂bean,调用它里面的专门用来创建bean的工厂方法来创建bean.
<bean id="personServiceFactory" class="cn.itcast.service.impl.PersonServiceBeanFactory"/> <!-- 将工厂类交给bean管理,实例化工厂类 --> <bean id="personService3" factory-bean="personServiceFactory" factory-method="createPersonService"/> <!-- 通过工厂里面的方法来创建bean -->
public PersonServiceBean createPersonService() { return new PersonServiceBean(); }
最后我们来测试一下,测试代码如下:
@Test public void instanceSpring() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); PersonService personService = (PersonService)ctx.getBean("personService"); personService.save(); } @Test public void instanceSpring2() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); PersonService personService = (PersonService)ctx.getBean("personService2"); personService.save(); } @Test public void instanceSpring3() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); PersonService personService = (PersonService)ctx.getBean("personService3"); personService.save(); }
测试结果如下:
三种实例化都可以,绝大部分都使用第一种实例化方案。
3.配置spring管理的bean的作用域
在前面,我们将bean交给spring容器进行管理,在客户端,我们只需要调用getBean方法就能获取beanbean实例。那么两次获取的实例是不是同一个实例呢?我们来测试一下@Test public void instanceSpring4() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); PersonService personService1 = (PersonService)ctx.getBean("personService"); PersonService personService2 = (PersonService)ctx.getBean("personService"); System.out.println(personService1 == personService2);; }控制台打印结果为true.则说明,默认情况下,这是一个单实例。
如果我们想每个getBean方法都获取到一个新的实例,这个时候我们该怎么做呢?这个就涉及到bean的作用域。
.singleton
在每个Spring IoC容器中一个bean定义只有一个对象实例。默认情况下会在容器启动时初始化bean,但我们可以指定Bean节点的lazy-int="true"来延迟初始化bean,这时候,只有第一次获取bean会才初始化bean。如:
<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" lazy-init="true"/>
如果想对所有bean都应用延迟初始化,可以在根节点beans设置default-lazy-init="true",如下
<beans default-lazy-init="true" ...>如果我们没有设置作用域的时候,默认的就是singleton作用的范围
.prototype
每次从容器获取bean都是新的对象。
通过scope来指定作用于范围。如:
<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" scope="prototype"/>
@Test public void instanceSpring4() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); PersonService personService1 = (PersonService)ctx.getBean("personService"); PersonService personService2 = (PersonService)ctx.getBean("personService"); System.out.println(personService1 == personService2);; }这个时候控制台打印出来的就是false.表示每调用一次getBean方法,它都会返回一个新的bean对象。
4.spring管理的bean的生命周期
当bean的作用域范围为单实例时,在什么时候进行实例化的呢?在默认构造函数中输出一句话,就可以知道了。
public PersonServiceBean() { System.out.println("我被初始化了..."); }所有的bean节点:
<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean"/><bean id="personService2" class="cn.itcast.service.impl.PersonServiceBeanFactory"
factory-method="createPersonServiceBean"/>
<bean id="personServiceFactory" class="cn.itcast.service.impl.PersonServiceBeanFactory"/>
测试代码:
@Test public void instanceSpring() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); //PersonService personService = (PersonService)ctx.getBean("personService"); //personService.save(); }后台打印结果为:
所以当作用于为singleton时,bean是在bean容器实例化时实例化的。
那么作用域为prototype时,bean是在什么时候实例化的呢?
将配置文件修改为:
<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" scope="prototype"/> <bean id="personService2" class="cn.itcast.service.impl.PersonServiceBeanFactory" factory-method="createPersonServiceBean" scope="prototype"/> <bean id="personServiceFactory" class="cn.itcast.service.impl.PersonServiceBeanFactory" scope="prototype"/>后,控制台打印结果为:
我们在来修改测试代码如下:
@Test public void instanceSpring() { ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); PersonService personService = (PersonService)ctx.getBean("personService"); //personService.save(); }
后台打印结果为:
所以作用域为prototype时,bean在调用getBean方法时初始化。
建议少用初始化延迟,这样不用等到运行期才能发现错误。
初始化资源与销毁bean
如果我们要对某些资源初始化,可以在bean中通过init-method来指定初始化方法<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" init-method="init"/>在bean实例中有该方法:
public void init() { System.out.println("初始化..."); }后台打印如下图:
可以在bean节点中用destroy-method来指定销毁方法,在关闭spring容器使就会调用该方法了。
<bean id="personService" class="cn.itcast.service.impl.PersonServiceBean" init-method="init" destroy-method="destroy"/>
public void destroy(){ System.out.println("销毁..."); }
@Test public void instanceSpring() { AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml"); ctx.close(); //PersonService personService = (PersonService)ctx.getBean("personService"); //personService.save(); }后台打印结果如下:
八月 07, 2015 8:04:01 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh 信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@47c5ee67: display name [org.springframework.context.support.ClassPathXmlApplicationContext@47c5ee67]; startup date [Fri Aug 07 20:04:01 CST 2015]; root of context hierarchy 八月 07, 2015 8:04:01 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions 信息: Loading XML bean definitions from class path resource [beans.xml] 八月 07, 2015 8:04:01 下午 org.springframework.context.support.AbstractApplicationContext obtainFreshBeanFactory 信息: Bean factory for application context [org.springframework.context.support.ClassPathXmlApplicationContext@47c5ee67]: org.springframework.beans.factory.support.DefaultListableBeanFactory@58cfbd2d 八月 07, 2015 8:04:01 下午 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons 信息: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@58cfbd2d: defining beans [personService,personService2,personServiceFactory,personService3]; root of factory hierarchy 我被实例化了... 初始化... 八月 07, 2015 8:04:01 下午 org.springframework.context.support.AbstractApplicationContext doClose 信息: Closing org.springframework.context.support.ClassPathXmlApplicationContext@47c5ee67: display name [org.springframework.context.support.ClassPathXmlApplicationContext@47c5ee67]; startup date [Fri Aug 07 20:04:01 CST 2015]; root of context hierarchy 八月 07, 2015 8:04:01 下午 org.springframework.beans.factory.support.DefaultSingletonBeanRegistry destroySingletons 信息: Destroying singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@58cfbd2d: defining beans [personService,personService2,personServiceFactory,personService3]; root of factory hierarchy 销毁... JDWP exit error JVMTI_ERROR_WRONG_PHASE(112): on checking for an interface [../../../src/share/back/util.c:1311]
相关文章推荐
- Java Concurrency in Practice中对象锁重入问题的理解
- struts2中的bean标签
- Java — 程序设计基础(Core Java I)
- jdk1.5新特性之自动装箱与拆箱
- jdk1.5新特性之增强for循环
- MyEclipse快捷键alt+/设置
- java注意事项
- Java — 开发环境(Core Java I)
- java关键字整理
- 2015届华为校园招聘机试题 (java实现)
- Eclipse工具条中添加下拉按钮
- 【JavaMail开发总结】开发前的配置
- HashMap和HashSet的区别
- Java程序设计之Constructor
- HashSet,TreeSet和LinkedHashSet的区别
- ,HashMap和Hashtable及HashSet的区别
- 使用Spring进行统一日志管理 + 统一异常管理
- Java IO流--IO包中的其他类
- java容器类---ArrayList
- springMVC获取request和response