深入探索spring技术内幕(二): 剖析spring管理Bean的原理与配置

来源:互联网 发布:如何随机生成一组数据 编辑:程序博客网 时间:2024/06/04 08:10

一、前言

spring是如何管理Bean的? 想必这是每一个初学spring的同学想弄清楚的问题, 好吧, 网上百度一下你会得到这样的答案:

服务启动时, 容器会解析配置文件, 并且会通过反射机制实例化配置中所有的类, 然后我们可以通过下面的方法获取Bean:

ApplicationContext ctx = new ClassPathXmlApplicationContext("spring.xml");
MyService myService = (MyService) ctx.getBean("myService");


二、模拟spring管理Bean

如果你只满足于此, 那就太没意思了, 要不咱自己模拟一下看看?


① 准备工作: 导Jar包

dom4j-1.6.1.jar 使用dom4j解析xml

jaxen-1.1-beta-6.jar 这是一个dom4j依赖包



② Bean对象定义封装

/** * Bean对象定义 * @author zhangjim */public class BeanDefinition {private String id;private String className;public BeanDefinition(String id, String className) {this.id = id;this.className = className;}public String getId() {return id;}public void setId(String id) {this.id = id;}public String getClassName() {return className;}public void setClassName(String className) {this.className = className;}}

③ Bean工厂

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;/** * Bean的工厂 * @author zhangjim */public class ClassPathXMLApplicationContext {private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();private Map<String, Object> sigletons = new HashMap<String, Object>();public ClassPathXMLApplicationContext(String filename) {this.readXML(filename);this.instanceBeans();}/** * 完成bean的实例化 */private void instanceBeans() {for (BeanDefinition beanDefinition : beanDefines) {try {if (beanDefinition.getClassName() != null && !"".equals(beanDefinition.getClassName().trim()))sigletons.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).newInstance());} catch (Exception e) {e.printStackTrace();}}}/** * dom4j读取xml配置文件 * @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);// 设置命名空间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);}}

1. 读取配置文件, 数据封装到BeanDefinition

2. 将BeanDefinition对象存入list

3. 遍历list, 通过反射产生对象并存入map

4. 调用getBean方法返回一个对象, 此对象为单例


④ 配置文件

<?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-2.5.xsd"><bean id="helloService" class="com.zdp.service.HelloService"></bean></beans>

⑤ 测试一下

import com.zdp.myspring.ClassPathXMLApplicationContext;public class  HelloService{public void sayHello() {System.out.println("say hello..."); }public static void main(String[] args) {ClassPathXMLApplicationContext ctx = new ClassPathXMLApplicationContext("beans.xml");HelloService helloService = (HelloService) ctx.getBean("helloService");helloService.sayHello();}}


三、spring三种实例化Bean的方式

① 使用类构造器实例化Bean, IoC容器使用默认空构造器

<bean id="helloBean1" class="com.zdp.service.impl.HelloBean"/>


② 使用静态工厂方法实例化Bean

<bean id="helloBean2" class="com.zdp.factory.HelloBeanStaticFactory" factory-method="createHelloBean"/>

public class HelloBeanStaticFactory {public static Hello createHelloBean() {return new HelloBean();}}


③ 使用实例工厂方法实例化Bean

<bean id="instanceFactory" class="com.zdp.factory.HelloBeanInstanceFactory"/> 
<bean id="helloBean3" factory-bean="instanceFactory" factory-method="createHelloBean"/>

public class HelloBeanInstanceFactory {public Hello createHelloBean() {return new HelloBean();}}


四、配置spring管理Bean的作用域

① singleton

<bean id="xxx" class="xxx" scope="singleton" />

只有一个对象实例, 默认情况下回再容器启动时初始化Bean, 但我们可以配置延迟初始化Bean


② prototype

<bean id="xxx" class="xxx" scope="prototype" />

每次从容器中获取Bean都是新的对象.


③ request

<bean id="xxx" class="xxx" scope="request" />

作用域基于web下有效


④ session

<bean id="xxx" class="xxx" scope="session" />

作用域基于web下有效


五、spring管理Bean的生命周期

Bean默认是在容器初始化时就创建, 如果配置了延迟加载, 则会延迟Bean的实例化

<bean id="xxx" class="xxx" scope="singleton" lazy-init="true" />   <!-- 只有第一次获取Bean才会初始化Bean -->

<beans default-lazy-init="true">   <!-- 对所有Bean都应用延迟初始化 -->


init和destory:

<bean id="xxx" class="xxx" scope="singleton" init-method="init" destroy-method="destory" />

public class HelloBeanTest {@Testpublic void testSayHello() {AbstractApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");        Hello hello =(Hello) ctx.getBean("helloBean");  // 调用init        hello.sayHello();        ctx.close(); // 调用destory}}





0 0
原创粉丝点击