Spring IOC控制反转 依赖注入DI

目录
1.使用IOC控制反转 中的DI依赖注入
   手工注入
      A:使用set 方法 注入 (1.使用 ref  2.使用bean)
      B.使用 构造 注入
   自动注入
      C 注解 (未)
2.自己编写 模仿 spring 的 注入功能
3.依赖 注入各种集合类型  set, map, list, properties

使用DI依赖注入dao( 编写dao---> 在service中使用 set方法注入dao-->配置)

package com.person.dao;

public interface PersonDao {
	public void add();
}


package com.person.dao.impl;

import com.person.dao.PersonDao;


public class PersonDaoBean implements PersonDao {
	public void add(){
		System.out.println("调用personDao中的add方法");
	}
}




import com.person.dao.PersonDao;
import com.person.service.PersonService;

public class PersonServiceBean implements PersonService {
	
	private PersonDao personDao; //注入 object
	
	private String name;  //注入基本类型 
	
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}



	//只需要提供 set方法 就可以  让 spring 的反射机制 给我们 注入dao 
	public void setPersonDao(PersonDao personDao) {
		this.personDao = personDao;
	}

	//调用 dao中的方法    
	public void add(){
		personDao.add();
	}

        
}



<!-- 使用 spring 管理 dao -->
	<bean id="personDao" class="com.person.dao.impl.PersonDaoBean">
	</bean>
	
	<!-- 这里配置后 就会有 spring来管理, 注意id 和name 的区别  -->
	<bean id="personService" class="com.person.service.impl.PersonServiceBean" lazy-init="true" >
		<!-- 配置 service 中引用 的dao 对象 为上面的 配置的 dao -->
		<property name="personDao" ref="personDao"/>
		<!-- 也可以使用这种 方式 注入   区别 在于   上面的 personDao就可以不用定义了 ,这样 其他的 service就不能访问 personDao, 根据需求使用  这两种方式
		<property name="personDao">
			<bean class="com.person.dao.impl.PersonDaoBean"/>
		</property> -->
		
		<!-- 为基本上属性注入值 -->
		<property name="name" value="JACK"/>
	</bean>



@Test   //测试  spring的 依赖注入
	public void init7(){
		ApplicationContext ctx=new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		PersonService personService=(PersonService)ctx.getBean("personService");
		personService.add();
	}


//发现  打印出 "调用personDao中的add方法" 这句话 说明 spring 的 IOC DI 成功.

2.下面我们来  模仿 spring的 注入功能  我想 这样你就更清楚了 (主要在我们昨天 编写的 mini spring 框架上 添加 属性的 注入功能)

在 加入一个 commons-beanutils-1.8.3.jar  帮助我们进行 类型转换

1.首先 定义 spring 配置中的 bean

package junit.test;

import java.util.ArrayList;
import java.util.List;

/**
 * 定义  保存 spring配置文件中的bean对象
 * @author Bin
 */
public class BeanDefinition {
	
	private String id;  //对应 spring配置文件中的id
	private String className;   //对应 spring配置文件中的class 
	
	//定义  bean中  属性的节点  集合 
	private List<PropertyDefinition> propertys= new ArrayList<PropertyDefinition>();
		
	
	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;
	}
	public BeanDefinition() {
	}
	
	public List<PropertyDefinition> getPropertys() {
		return propertys;
	}
	public void setPropertys(List<PropertyDefinition> propertys) {
		this.propertys = propertys;
	}
	public BeanDefinition(String id, String className) {
		this.id = id;
		this.className = className;
	}
	
	
}


2.定义 bean节点中的属性  property

package junit.test;

public class PropertyDefinition {
	private String name;  //对应配置 文件中的name 
	private String ref;   //对应配置 文件中的ref
	private String value;  //为基本属性注入值
	
	
	public String getValue() {
		return value;
	}
	public void setValue(String value) {
		this.value = value;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getRef() {
		return ref;
	}
	public void setRef(String ref) {
		this.ref = ref;
	}
	public PropertyDefinition() {
		super();
		// TODO Auto-generated constructor stub
	}
	public PropertyDefinition(String name, String ref) {
		super();
		this.name = name;
		this.ref = ref;
	}
	public PropertyDefinition(String name, String ref, String value) {
		super();
		this.name = name;
		this.ref = ref;
		this.value = value;
	}
	
	
	
}



3.定义 ClassPathXmlApplicationContext 

package junit.test;


import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.ConvertUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.XPath;
import org.dom4j.io.SAXReader;

import com.sun.xml.internal.fastinfoset.stax.events.Util;


/*
 * 编写自己的  mini spring 容器
 * 来模拟spring 的工作
 */
public class MySpringClassPathXmlApplicationContext {
	
	//保存 配置文件中的 bean 的信息  
	private List<BeanDefinition> beandefines=new ArrayList<BeanDefinition>();
	
	//保存初始化 后的对象
	private Map<String,Object> sigletons=new HashMap<String,Object>();
	
	
	//构造方法
	public MySpringClassPathXmlApplicationContext(String fileName) {
		//读取配置文件
		this.readXml(fileName);
		//初始化所有的bean
		this.instanceBean();
		//为所有bean 依赖注入 属性 
		this.injectObject();
	}


	/**==================
	 *   读取xml配置文件
	 * ==================
	 * @author Bin
	 * @param fileName
	 */
	private void readXml(String fileName) {
		SAXReader saxReader=new SAXReader();
		Document doucment=null;
		try {
			URL xmlPath=this.getClass().getClassLoader().getResource(fileName);
			doucment=saxReader.read(xmlPath);
			Map<String,String> nsMap=new HashMap<String,String>();
			//给spring配置文件的命名空间  一个别名 ns
			nsMap.put("ns","http://www.springframework.org/schema/beans"); //加入命名空间  xmlns: spring配置文件中的
			XPath xsub=doucment.createXPath("//ns:beans/ns:bean"); //创建 beans/bean 查询路径
			
			xsub.setNamespaceURIs(nsMap); //设置命名空间
			List<Element> beans=xsub.selectNodes(doucment); //获取文档下的所有bean节点
			
			for (Element element : beans) {
				String id=element.attributeValue("id"); //获取 id的属性值
				String clazz=element.attributeValue("class"); // 获取 class属性

				//类是 spring中的 : org.springframework.beans.factory.config.BeanDefinition;
				BeanDefinition beandefine=new BeanDefinition(id,clazz);
				
				//解析 bean节点中的property 属性节点
				XPath propertysub=element.createXPath("ns:property"); //创建 property的查询路径  //使用相对路径 
				propertysub.setNamespaceURIs(nsMap); //设置命名空间
				List<Element> propertys=propertysub.selectNodes(element); //根据 查询路径 在  这个元素中查找  子元素
				for (Element property : propertys) { //取出查找到 的 property 子节点
					String propertyName=property.attributeValue("name");
					String propertyRef=property.attributeValue("ref");
					String propertyValue=property.attributeValue("value");
					PropertyDefinition propertyDefinition= new PropertyDefinition(propertyName,propertyRef,propertyValue);
					//放入 bean 的property 集合中 
					beandefine.getPropertys().add(propertyDefinition);
				}
				beandefines.add(beandefine);  //将这个bean保存的 集合中
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**===================================
	 *   完成Bean 的实例化
	 * ===================================
	 * @author Bin
	 */
	private void instanceBean() {
		for (BeanDefinition beandefine : beandefines) {
			try {
				if(!Util.isEmptyString(beandefine.getClassName()))
					sigletons.put(beandefine.getId(), Class.forName(beandefine.getClassName().trim()).newInstance());
			}catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
	
	//注入对象  主要是  根据 set 方法  
	private void injectObject() {
		try{
			//遍历 spring配置中的 bean节点信息的集合 (id class)
			for (BeanDefinition beandefine : beandefines) {
				//根据id 到 初试化好了的 对象集合中 查找对象
				Object bean=sigletons.get(beandefine.getId());
				if(bean!=null){
					//如果对象不为空 就获取这个对象的 所有属性信息 
					PropertyDescriptor[] ps=Introspector.getBeanInfo(bean.getClass()).getPropertyDescriptors();
					//遍历  bean节点中  所有的 property 子节点集合 
					for(PropertyDefinition propertyDefinition:beandefine.getPropertys()){
						//遍历 初始化好后的 对象中的 属性 描述
						for(PropertyDescriptor properDesc:ps){
							//如果 两个 属性名相等  就说明找到了这个对象中的属性了
							if(propertyDefinition.getName().equals(properDesc.getName())){
								Method setter=properDesc.getWriteMethod(); //获取属性的setter方法 可  能是 public  ,private 类型
								if(setter!=null){
									Object value=null;
									if(!setter.isAccessible()){ //判断是否是 私有只读的 
										   setter.setAccessible(true);  //强制访问 私有属性的 setter 方法
									}
									if(!Util.isEmptyString(propertyDefinition.getRef())){ //说明是引用类型
										//根据属性节点中的ref 到 sigletons 中取出对象 
										value=sigletons.get(propertyDefinition.getRef());
									}else{//说明 是基本类型  
										value=ConvertUtils.convert(propertyDefinition.getValue(),properDesc.getPropertyType());
									}
									setter.invoke(bean, value);  //给 某个对象某个方法 注入一个值
								}
								break;  //注入 完一个 属性后 就跳出  继续为下一个属性 赋值
							}
						}
					}
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}
		
	}
	
	
	/**=======================
	 *    获取bean 
	 * =======================
	 * @param beanName
	 * @return
	 */
	public Object getBean(String beanName){
		return this.sigletons.get(beanName);
	}
	
}



4.测试

	@Test  //测试自己  编写的 spring 注入 功能
	public void init8(){
		MySpringClassPathXmlApplicationContext ctx= new MySpringClassPathXmlApplicationContext("applicationContext.xml");
		PersonService personService=(PersonService)ctx.getBean("personService");
		personService.add();
	}


如果上面的 打印出了 "调用personDao中的add方法" 说明我们手动的 编写的 spring注入 成成功实现了 注入对象和 注入基本类型. 我想这样 不会告诉我说你不懂 spring IOC了吧  呵呵

3.依赖 注入各种集合类型  set, map, list, properties

package com.person.service;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public interface PersonService {
	
	//为了能在  前台访问 所以就提供这样的一个方法 用来放回注入后的set 集合
	public Set<String> getSets();
	public List<String> getLists();
	public Properties getProperties();
	public Map<String, String> getMaps();
	
	
	public void save();
	public void add();
}


package com.person.service.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import com.person.dao.PersonDao;
import com.person.service.PersonService;

public class PersonServiceBean implements PersonService {
	
	//引用对象
	private PersonDao personDao; //注入 object
	//基本类型 
	private String name;  //注入基本类型 
	// Set 集合类型
	private Set<String> sets=new HashSet<String>();
	// list 集合类型
	private List<String> lists=new ArrayList<String>();
	// Properties 集合类型
	private Properties properties=new Properties();
	// Map 集合类型
	private Map<String,String> maps=new HashMap<String,String>();
	
	// get set
}


<?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/context 
    http://www.springframework.org/schema/context/spring-context-3.0.xsd
    http://www.springframework.org/schema/beans   
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd "> 
	
	<!-- 使用 spring 管理 dao -->
	<bean id="personDao" class="com.person.dao.impl.PersonDaoBean">
	</bean>
	
	<!-- 这里配置后 就会有 spring来管理, 注意id 和name 的区别  -->
	<bean id="personService" class="com.person.service.impl.PersonServiceBean" lazy-init="true" >
		<!-- 配置 service 中引用 的dao 对象 为上面的 配置的 dao -->
		<property name="personDao" ref="personDao"/>
		<!-- 也可以使用这种 方式 注入   区别 在于   上面的 personDao就可以不用定义了 ,这样 其他的 service就不能访问 personDao, 根据需求使用  这两种方式
		<property name="personDao">
			<bean class="com.person.dao.impl.PersonDaoBean"/>
		</property> -->
		
		<!-- 为基本上属性注入值 -->
		<property name="name" value="JACK"/>
		
		<property name="sets">
			<set>
				<value>第一个</value>
				<value>第二个</value>
				<value>第三个</value>
				<value>第四个</value>
			</set>
		</property>
		
		<property name="lists">
			<list>
				<value>第一个List元素</value>
				<value>第二个List元素</value>
				<value>第三个List元素</value>
			</list>
		</property>
		
		<property name="properties">
			<props>
				<prop key="key1">value1</prop>
				<prop key="key2">value2</prop>
				<prop key="key3">value3</prop>
			</props>
		</property>
		<property name="maps">
			<map>
				<entry key="key-1" value="value-1"/>
				<entry key="key-2" value="value-2"/>
				<entry key="key-3" value="value-3"/>
			</map>
		</property>
	</bean>
</beans>


	
	@Test   //测试  spring的 依赖注入
	public void init9(){
		ApplicationContext ctx=new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		PersonService personService=(PersonService)ctx.getBean("personService");
		personService.add();
		System.out.println("============set============");
		for (String name : personService.getSets()) {
			System.out.println(name);
		} 
		System.out.println("============List============");
		for (String desc : personService.getLists()) {
			System.out.println(desc);
		}
		System.out.println("============properties============");
		for (Object key : personService.getProperties().keySet()) {
			System.out.println(key+"="+personService.getProperties().getProperty(key.toString()));
		}
		System.out.println("============maps============");
		for (String key: personService.getMaps().keySet()) {
			System.out.println(key+"="+personService.getMaps().get(key));
		}
	}


5.使用构造注入

package com.person.service.impl;

import com.person.dao.PersonDao;
import com.person.service.PersonService;

public class PersonServiceBean implements PersonService {
	
	//引用对象
	private PersonDao personDao; //注入 object
	//基本类型 
	private String name;  //注入基本类型 
	
	// 使用构造注入
	public PersonServiceBean(PersonDao personDao, String name) {
		this.personDao = personDao;
		this.name = name;
	}
	
}

	<!-- 使用 spring 管理 dao -->
	<bean id="personDao" class="com.person.dao.impl.PersonDaoBean">
	</bean>
	<bean id="personService4" class="com.person.service.impl.PersonServiceBean" >
		<constructor-arg index="0" type="com.person.dao.PersonDao" ref="personDao"/>
		<constructor-arg index="1" type="java.lang.String" value="欢迎踩踩!"/>
	</bean>


@Test
	public void init10(){
		ApplicationContext ctx=new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		PersonService personService=(PersonService)ctx.getBean("personService4");
		personService.add();
	}


//从上面可以测试出 我们在给构造函数 给参数的时候 可以根据 name 和 index 来赋值  type是可选的
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值