首页 > 代码库 > Spring笔记(一):Ioc 之 Bean的管理

Spring笔记(一):Ioc 之 Bean的管理

前提:

1、需要 spring、dom4j、junit、commons-logging等的jar包, 配置web.xml,新增 applicationContext.xml

2、Spring主要核心是:

1)控制反转(IOC):以前传统的java开发模式中,当需要一个对象时我们,我们会自己使用new或者getInstance等直接或者间接调用构造方法创建一个对象,而在Spring开发模式中,Spring容器使用了工厂模式为我们创建了所需要的对象,我们使用时不需要自己去创建,直接调用Spring为我们提供的对象即可,这就是控制反转的思想。实例化一个java对象有三种方式:使用类构造器,使用静态工厂方法,使用实例工厂方法,当使用spring时我们就不需要关心通过何种方式实例化一个对象,spring通过控制反转机制自动为我们实例化一个对象。


2)依赖注入(DI):Spring使用java Bean对象的Set方法或者带参数的构造方法为我们在创建所需对象时将其属性自动设置所需要的值的过程就是依赖注入的基本思想。


3)面向切面编程(AOP):在面向对象编程(OOP)思想中,我们将事物纵向抽象成一个个的对象。而在面向切面编程中,我们将一个个对象某些类似的方面横向抽象成一个切面,对这个切面进行一些如权限验证,事物管理,记录日志等公用操作处理的过程就是面向切面编程的思想。

一、Spring的 Ioc 简介


(一)Spring容器管理Bean

1、创建Bean :接口和实现类

<span style="font-family:Arial;font-size:18px;">package main.java.com.spring.ioc.base.service;

/**
 * 
 * PersonService
 * 
 * @desc
 * @author SAM-SHO
 * @Dec 25, 2014
 */
public interface PersonService {
	public void save();
}
</span>
<span style="font-family:Arial;font-size:18px;">/**
 * 
 */
package main.java.com.spring.ioc.base.service.impl;

import main.java.com.spring.ioc.base.service.PersonService;

/**
 * PersonServiceImpl
 * @desc
 * @author SAM-SHO
 * @Dec 25, 2014
 */
public class PersonServiceImpl implements PersonService {

	public PersonServiceImpl() {
		System.out.println("我被实例化了");
	}

	@Override
	public void save() {
		System.out.println("我是 save() 方法");

	}
	
	/**
	 * 初始化方法
	 */
	public void init(){
		System.out.println("我是初始化方法");
	}
	
	/**
	 * 销毁方法
	 */
	public void destroy(){
		System.out.println("我是销毁方法,关闭资源");
	}
	
	

}
</span>


2、配置文件:

1)在 applicationContext.xml 配置文件中引入Bean 的xml schema。

2)管理Bean :<bean>标签

<span style="font-family:Arial;font-size:18px;">	<!-- name与id功能一直,但是id为xml的默认属性可以校验,而name则可以取一些特殊符号的名字如 。。。?aa? -->
	<!-- 这样配置好后,会交由spring创建和管理,我们只需要去spring容器中获取 -->
	<bean id="personServiceImpl" class="main.java.com.spring.ioc.base.service.impl.PersonServiceImpl">
	</bean>
</span>

3、测试:

<span style="font-family:Arial;font-size:18px;">//		ApplicationContext cxt = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
		ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
		PersonService tPersonService = cxt.getBean("personServiceImpl", PersonServiceImpl.class);//利用接口接收
		tPersonService.save(); //【输出】我是 save() 方法
</span>


(二)Spring管理Bean的原理

1、自定义容器类

<span style="font-family:Arial;font-size:18px;">package test.java.com.spring.ioc.base;

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;

/**
 * 
 * MyClassPathXMLApplicationContext
 * 
 * @title 自定义容器
 * @desc
 * @author SAM-SHO
 * @Dec 25, 2014
 */
public class MyClassPathXMLApplicationContext {
	private List<BeanDefinition> beanDefines = new ArrayList<BeanDefinition>();
	private Map<String, Object> sigletons = new HashMap<String, Object>();

	public MyClassPathXMLApplicationContext(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();
			}
		}
	}

	/**
	 * 读取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);
	}
}
</span>

2、自定义DTO,数据传输类:

<span style="font-family:Arial;font-size:18px;">package test.java.com.spring.ioc.base;

/**
 * 
 * BeanDefinition
 * @title Bean对象
 * @desc
 * @author SAM-SHO
 * @Dec 25, 2014
 */
public class BeanDefinition {
	private String id;//id属性
	private String className;//class属性
	
	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;
	}
	
}
</span>

3、测试:使用自定义的容器管理Bean的初始化

<span style="font-family:Arial;font-size:18px;">	//初始化spring容器
	@Test
	public void instanceSpring() {
		
//		ApplicationContext cxt = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
		ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
		PersonService tPersonService = cxt.getBean("personServiceImpl", PersonServiceImpl.class);//利用接口接收
		tPersonService.save(); //【输出】我是 save() 方法
		
		//自定义获取Bean
		MyClassPathXMLApplicationContext mcxt = new MyClassPathXMLApplicationContext("applicationContext.xml");
		tPersonService = (PersonService) mcxt.getBean("personServiceImpl");
		tPersonService.save();//【输出】我是 save() 方法
	}
</span>


二、Spring的三种实例化Bean的方式

(一)类构造器实例化Bean,常用,即上面的实例。

1、对应的代码类为:

<span style="font-family:Arial;font-size:18px;">public class PersonServiceImpl implements PersonService {

	public PersonServiceImpl() {
		System.out.println("我被实例化了");
	}

	@Override
	public void save() {
		System.out.println("我是 save() 方法");

	}
}</span>



2、配置文件配置:

<span style="font-family:Arial;font-size:18px;">	<!-- 1-1类构造器实例化Bean -->
	<!-- name与id功能一直,但是id为xml的默认属性可以校验,而name则可以取一些特殊符号的名字如 。。。?aa? -->
	<!-- 这样配置好后,会交由spring创建和管理,我们只需要去spring容器中获取 -->
	<bean id="personServiceImpl" class="main.java.com.spring.ioc.base.service.impl.PersonServiceImpl">
	</bean>
</span>



(二)静态工厂方法实例化Bean

1、对应的代码类为:创建工厂类,新建静态方法。

<span style="font-family:Arial;font-size:18px;">/**
 * 
 * PersonServiceFactory
 * @title 工厂类
 * @desc 静态工厂方法实例化Bean
 * @author SAM-SHO
 * @Dec 26, 2014
 */
public class PersonServiceFactory {
	
	/**
	 * 静态方法,创建 PersonServiceImpl 对象
	 * @return
	 */
	public static PersonServiceImpl createPersonService(){
		
		return new PersonServiceImpl();
	}
}</span>

2、配置文件配置:factory-method="createPersonService" 

<span style="font-family:Arial;font-size:18px;">	<!-- 1-2静态工厂方法实例化Bean -->
	<bean id="personServiceImpl2"  class="main.java.com.spring.ioc.base.service.impl.PersonServiceFactory"
		factory-method="createPersonService" >
	</bean>
</span>



(三)实例工厂方法实例化Bean,配置的时候,先实例化工厂类。

1、对应的代码类为:在工厂类中新增非静态方法

<span style="font-family:Arial;font-size:18px;">	
	/**
	 * 非静态的方法,创建PersonServiceImpl 对象
	 * @return
	 */
	public PersonServiceImpl createPersonService2(){
		
		return new PersonServiceImpl();
	}
</span>



2、配置文件配置:非静态方法的调用,需先实例化工厂类。factory-bean 和 factory-method

<span style="font-family:Arial;font-size:18px;">	<!-- 1-3实例工厂方法实例化Bean  -->
	<!-- 先实例化工厂类,然后在实例化需要的Bean -->
	<bean id="personServiceFactory" class="main.java.com.spring.ioc.base.service.impl.PersonServiceFactory"></bean> 
	<bean id="personServiceImpl3" factory-bean="personServiceFactory" factory-method="createPersonService2"></bean>
</span>


(四)测试:

<span style="font-family:Arial;font-size:18px;">	//Spring的三种实例化Bean的方式
	@Test
	public void ManageBean3Mothed() {
		
		// 1-类构造器实例化Bean,常用
		ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
		PersonService tPersonService = cxt.getBean("personServiceImpl", PersonServiceImpl.class);//利用接口接收
		tPersonService.save(); //【输出】我是 save() 方法
		
		// 2-静态工厂方法实例化Bean
		PersonService tPersonService2 = cxt.getBean("personServiceImpl2", PersonServiceImpl.class);//利用接口接收
		tPersonService2.save(); //【输出】我是 save() 方法
		
		// 3-实例工厂方法实例化Bean,配置的时候,先实例化工厂类
		PersonService tPersonService3 = cxt.getBean("personServiceImpl3", PersonServiceImpl.class);//利用接口接收
		tPersonService3.save(); //【输出】我是 save() 方法
	}
</span>



三、Spring管理的Bean的作用域 Scope

(一)测试spring容器创建对象的实例个数。

1、配置文件:

<span style="font-family:Arial;font-size:18px;">	<bean id="personServiceImpl" class="main.java.com.spring.ioc.base.service.impl.PersonServiceImpl">
	</bean>
</span>

2、测试代码:true,说明是单例,同一个对象。

<span style="font-family:Arial;font-size:18px;">		// 1-查看Bean对象的实例
		ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
		PersonService tPersonService = cxt.getBean("personServiceImpl", PersonServiceImpl.class);//利用接口接收
		PersonService tPersonService2 = cxt.getBean("personServiceImpl", PersonServiceImpl.class);//利用接口接收
		System.out.println(tPersonService==tPersonService2);//【输出】true,说明是单例
</span>


(二)Bean的作用域 Scope:默认在每个spring Ioc容器中一个bean定义只有一个对象实例。

1、Scope的取值:

1)singleton:默认,单例。

2)prototype:每次都是新的。管理struts的action,一定要是prototype。

3)request、session、global session。


2、配置 scope="prototype"

1)配置文件:

<span style="font-family:Arial;font-size:18px;">	<!-- 2-Bean的作用域  -->
	<bean id="personServiceImpl4" scope="prototype"  class="main.java.com.spring.ioc.base.service.impl.PersonServiceImpl">
	</bean>
</span>

2)测试代码:

<span style="font-family:Arial;font-size:18px;">	// Spring管理的bean的作用域
	@Test
	public void ManageBeanScope() {
		
		// 1-查看Bean对象的实例
		ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
		PersonService tPersonService = cxt.getBean("personServiceImpl", PersonServiceImpl.class);//利用接口接收
		PersonService tPersonService2 = cxt.getBean("personServiceImpl", PersonServiceImpl.class);//利用接口接收
		System.out.println(tPersonService==tPersonService2);//【输出】true,说明是单例
		
		
		/*
		 * 2-Bean的作用域 Scope:在每个spring Ioc容器中一个bean定义只有一个对象实例。
		 * singleton:默认,单例
		 * prototype:每次都是新的
		 * request
		 * session
		 * global session
		 */
		// 配置 	<bean id="personServiceImpl4" scope="prototype"  class="main.java.com.spring.ioc.base.service.impl.PersonServiceImpl"></bean>
		PersonService tPersonService4 = cxt.getBean("personServiceImpl4", PersonServiceImpl.class);//利用接口接收
		PersonService tPersonService4_1 = cxt.getBean("personServiceImpl4", PersonServiceImpl.class);//利用接口接收
		System.out.println(tPersonService4==tPersonService4_1);//【输出】false,说明是每次都是新的对象
		
	}
</span>


四、Spring管理的Bean的生命周期

1、默认情况下会在容器启动时初始化Bean,但是,当Scope = "prototype"的时候,Bean只会在getBean()方法的时候实例化。

2、可以指定Bean节点的lazy-init="true" 来延迟初始化Bean,这时候,只有第一次获取Bean 时才会初始化Bean,<bean lazy-init="true"。

3、如果想对所有bean 都应用延迟初始化,可以在根节点<beans default-lazy-init="true"> 。

4、init-method="" 指定初始化方法;destroy-method="" 指定销毁方法

(一)默认初始化:

1、默认为容器启动时初始化Bean。

1)配置:

<span style="font-family:Arial;font-size:18px;">	<bean id="personServiceImpl" class="main.java.com.spring.ioc.base.service.impl.PersonServiceImpl">
	</bean>
</span>

2)测试代码:初始化容器即可

<span style="font-family:Arial;font-size:18px;">ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");</span>

3)【输出】:PersonServiceImpl构造方法中的输出:我被实例化了


2、Scope = "prototype" 的例外

1)配置:

<span style="font-family:Arial;font-size:18px;">	<bean id="personServiceImpl" scope="prototype" class="main.java.com.spring.ioc.base.service.impl.PersonServiceImpl">
	</bean>
</span>

2)测试:需要在getBean()的时候才会实例化

<span style="font-family:Arial;font-size:18px;">		//1-默认:这边容器启动的时候就会对Bean实例化
		//但是,当Scope = "prototype"的时候,Bean只会在getBean()方法的时候实例化
//		ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");
</span>


(二)懒加载初始化:lazy-init="true"

1、配置文件:

<span style="font-family:Arial;font-size:18px;">	<!-- 3-Bean 的生命周期: lazy-init="true"延迟初始化  -->
	<bean id="personServiceImpl5" lazy-init="true"  class="main.java.com.spring.ioc.base.service.impl.PersonServiceImpl">
	</bean>
</span>

2、测试代码:本来是初始化的时候即会实例化,但是只有调用getBean()的时候才会实例化。

<span style="font-family:Arial;font-size:18px;">// 2-使用lazy-init="true",延迟初始化
ApplicationContext cxt2 = new ClassPathXmlApplicationContext("applicationContext.xml");
PersonService tPersonService5 = cxt2.getBean("personServiceImpl5", PersonServiceImpl.class);//利用接口接收
</span>

(三)指定初始化与销毁方法:init-method="" ;destroy-method="" 

1、配置文件:指定Bean中初始化与销毁的方法名称。

<span style="font-family:Arial;font-size:18px;">	<!-- init-method="" 指定初始化方法 destroy-method="" 指定销毁方法 -->
	<bean id="personServiceImpl6" init-method="init" destroy-method="destroy" class="main.java.com.spring.ioc.base.service.impl.PersonServiceImpl">
	</bean>
</span>


2、测试代码:

1)init-method="":初始化。

<span style="font-family:Arial;font-size:18px;">		// 3-init-method="" 指定初始化方法。先实例化,再调用初始化方法
		ApplicationContext cxt3 = new ClassPathXmlApplicationContext("applicationContext.xml");
		PersonService tPersonService6 = cxt3.getBean("personServiceImpl6", PersonServiceImpl.class);//【输出】我是初始化方法
</span>

2)destroy-method="" :销毁方法。

<span style="font-family:Arial;font-size:18px;">		// 4-destroy-method="" 指定销毁方法 
		// AbstractApplicationContext 正常关闭容器
		AbstractApplicationContext cxt4 = new ClassPathXmlApplicationContext("applicationContext.xml");
		cxt4.close();//【输出】 我是销毁方法,关闭资源
</span>


Spring笔记(一):Ioc 之 Bean的管理