目录
1.使用IOC控制反转 中的DI依赖注入 (两种配置方式)
2.自己编写 模仿 spring 的 注入功能
[b][color=red]使用DI依赖注入dao( 编写dao---> 在service中使用 set方法注入dao-->配置)[/color][/b]
//发现 打印出 "调用personDao中的add方法" 这句话 说明 spring 的 IOC DI 成功.
[b][color=red]2.下面我们来 模仿 spring的 注入功能 我想 这样你就更清楚了 [/color][/b](主要在我们昨天 编写的 mini spring 框架上 添加 属性的 注入功能)
在 加入一个 commons-beanutils-1.8.3.jar 帮助我们进行 类型转换
1.首先 定义 spring 配置中的 bean
2.定义 bean节点中的属性 property
3.定义 ClassPathXmlApplicationContext
4.测试
如果上面的 打印出了 "调用personDao中的add方法" 说明我们手动的 编写的 spring注入 成成功实现了 注入对象和 注入基本类型. 我想这样 不会告诉我说你不懂 spring IOC了吧 呵呵
1.使用IOC控制反转 中的DI依赖注入 (两种配置方式)
2.自己编写 模仿 spring 的 注入功能
[b][color=red]使用DI依赖注入dao( 编写dao---> 在service中使用 set方法注入dao-->配置)[/color][/b]
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 成功.
[b][color=red]2.下面我们来 模仿 spring的 注入功能 我想 这样你就更清楚了 [/color][/b](主要在我们昨天 编写的 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了吧 呵呵