您的位置:首页 > 编程语言 > Java开发

Spring IOC控制反转 依赖注入DI

2017-03-27 11:09 295 查看
目录

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是可选的
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: