Spring IOC统制反转 依赖注入DI
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-->配置)
//发现 打印出 "调用personDao中的add方法" 这句话 说明 spring 的 IOC DI 成功.
2.下面我们来 模仿 spring的 注入功能 我想 这样你就更清楚了 (主要在我们昨天 编写的 mini spring 框架上 添加 属性的 注入功能)
在 加入一个 commons-beanutils-1.8.3.jar 帮助我们进行 类型转换
1.首先 定义 spring 配置中的 bean
2.定义 bean节点中的属性 property
3.定义 ClassPathXmlApplicationContext
4.测试
如果上面的 打印出了 "调用personDao中的add方法" 说明我们手动的 编写的 spring注入 成成功实现了 注入对象和 注入基本类型. 我想这样 不会告诉我说你不懂 spring IOC了吧 呵呵
3.依赖 注入各种集合类型 set, map, list, properties
5.使用构造注入
//从上面可以测试出 我们在给构造函数 给参数的时候 可以根据 name 和 index 来赋值 type是可选的
目录
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是可选的
1 楼
befairy
1 小时前
Mark....谢谢分享。。。