简单模拟了一下spring的注入功能,重点在于对这四点的把握。
第一点,XXContext类的理解和content对象的区别。
第二点, ClassPathXmlApplicationContext是BeanFactory的实现类。并且ClassPathXmlApplicationContext中定义了bean容器。(就是放所有的bean)
第三点,beanfactory的主要作用就是根据名字拿到相应的bean。
第四点,具体的注入本质就是反射调用SetBean方法,来为其赋值。
第五点,实际在spring中,beanfactory实现了bean的一些功能,但ClassPathXmlApplicationContext除了实现这些,还实现如控制bean生命周期等功能,所以,一般使用ClassPathXmlApplicationContext,但要知道,他是实现了beanfactory的。
具体每一点可见下面例子中的注释,userdao,userservice就不写了,只是userservice种有一个userdao属性,有get/set方法而已。
<beans>
<bean id="userDaoImpl" class="springTest.dao.impl.UserDaoImpl"/>
<bean id="userService" class="springTest.service.UserService" >
<property name="userDao" bean="userDaoImpl"></property>
</bean>
</beans>
beanFactory类:
package springTest.spring;
/**
* beanfactory的主要作用就是根据名字拿到相应的bean。
*/
public interface BeanFactory {
public Object getBeans(String name);
}
ClassPathXmlApplicationContext类:
package springTest.spring;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import test.lee.ReadXmlTest;
/**
**************************
***一***XXContext类的理解***
**************************
*
* XXContext类的理解和content对象的区别:
* 1.XXContext类并不是说会产生content对象,而是会加载(利用)content对象。
* 2.content对象 类似一个参数,XXContext类 类似一个方法。
*
* 作用:
* 这是策略模式的利用,其本质是赋值一些方法,就是 ClassPathXmlApplication类的一些方法的 赋值,而参数是这个content对象。
*
* 所以不要单纯的理解为上下文,其实质是 所有方法的 赋值。也可是说是上下文。
*********************************************************************
*********************************************************************
***二***要记住 ClassPathXmlApplicationContext是BeanFactory的实现类。***
*********************************************************************
* 它中定义了bean的容器
*
* beanfactory的主要作用就是根据名字拿到相应的bean。
*
*/
public class ClassPathXmlApplicationContext implements BeanFactory {
/**
* beans 就是一个map类型的容器,它存放所有的bean,
*
* 1.在服务器启动的时候,初始化所有的bean。
* 2.把所有bean放到容器中去。
* 3.用的时候,从容器中取出bean。
* 注: 理解“取” 这个 取,其实就是注入了。在初始化一些bean时候,就会用到另一些bean,这其实就是取出。
*
* 为bean中属性初始化bean的思路
*
* 1.首先,把所有bean都放到容器中。
* 2.通过配置文件获取到bean的要注入的bean。也就是property。得到注入bean。
* 3.通过name设置setBean的方法。(主要是字符串处理)
* 4.通过反射调用setBean方法,为其注入。实现赋值。
*/
private Map<String,Object> beans = new HashMap<String,Object>();
public ClassPathXmlApplicationContext() throws JDOMException, IOException, InstantiationException, IllegalAccessException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
SAXBuilder sb = new SAXBuilder();
Document doc = sb.build(ReadXmlTest.class.getClassLoader().getResourceAsStream("beans.xml")); // 构造文档对象
Element root = doc.getRootElement(); // 获取根元素
List list = root.getChildren("bean");// 取名字为bean的所有元素
for (int i = 0; i < list.size(); i++) {
Element element = (Element) list.get(i);//获得一个bean
String id = element.getAttributeValue("id"); //获得bean的属性值
String clazz = element.getChildText("class");// 取bean子元素class的内容
System.out.println(id+":"+clazz);
Object o = Class.forName(clazz).newInstance();//建立bean对象
beans.put(id, o);//将bean放入容器
//取到所有的 property
for(Element properElement:(List<Element>)element.getChildren("property")){
String name =properElement.getAttributeValue("name");
String bean =properElement.getAttributeValue("bean");
Object beanObject = beans.get(bean);
//拼接字符串 方法名字 setXx()
String methodName = "set"+ name.substring(0,1).toUpperCase()+name.substring(1);
//利用 反射实现 该方法的调用
//数组的作用是userDao接口的实现类 userDaoimpl,它可以实现多个接口,所以是数组
Method m = o.getClass().getMethod(methodName, beanObject.getClass().getInterfaces()[0]);
m.invoke(o, beanObject);
}
}
}
@Override
public Object getBeans(String name) {
// TODO Auto-generated method stub
return beans.get(name);
}
}
总结一下,bean的使用呢,首先是放到一个容器里,所以要知道这一点。其次要明白,注入的那个bean,是通过反射调用set方法实现的,所以一定要写set方法。最后呢,是对策略模式的理解,放在这里,就是要知道,Context实现了beanfactory接口,完成了把他放入容器和发射调用SET注入两个功能。