在使用spring框架时,不在程序里new对象,而是将对象都交给了spring去管理,在需要对象时,去spring容器里获取
例如,在spring配置文件里定义一个bean
<bean id="userDao" class="com.wh.dao.impl.UserDaoImpl"></bean>
在需要UserDaoImpl对象时,不在去new,而是直接问容器要
public void testInversion(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
userDao.save();
}
可以看出来对象一定是都放在了applicationContext里,bean对象就是它管理的
工作原理应该就是applicationContext解析了applicationContext.xml文件后,拿到了类的全路径,通过反射创建对象并保存到了貌似是一个map的集合里
该map的key就是的id属性,value就是value或rel属性
模拟一个简单的ApplicationContext
假设已有bean配置文件bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>
<bean id="personDao" class="com.wh.dao.impl.PersonDaoImpl"></bean>
<bean id="personService" class="com.wh.service.impl.PersonServiceImpl">
<property name="personDao" ref="personDao"></property>
</bean>
</beans>
SpringXmlApplicationContext
public class SpringXmlApplicationContext {
// 模仿spring存储对象的容器, key就是<bean id="">, value就是<bean class="">
private Map<String,Object> map=new HashMap<String,Object>();
public SpringXmlApplicationContext(String file){
try {
SAXReader saxReader=new SAXReader();
InputStream inputStream= SpringXmlApplicationContext.class.getClassLoader().getResourceAsStream(file);
Document document = saxReader.read(inputStream);
// 获取根元素
Element rootElement = document.getRootElement();
// 获取根元素下所有子元素
List<Element> elements = rootElement.elements();
// 循环所有的bean
for (Element element : elements) {
String key=element.attributeValue("id");
String className=element.attributeValue("class");
Class clazz=Class.forName(className);
// 通过反射创建对象
Object value=clazz.newInstance();
// 将创建的对象放到spring容器
map.put(key,value);
// 找到每个bean标签下的所有property子元素
List<Element> propertyList= element.elements("property");
// 依赖注入
if(propertyList!=null && propertyList.size()>0){
// 循环propertyList
for (Element propertyElement : propertyList) {
//找到property标签中的name属性的值
String name= propertyElement.attributeValue("name");
//找到property标签中的ref属性的值
String ref=propertyElement.attributeValue("ref");
byte[] names=name.getBytes();
names[0]=(byte)(names[0]-32);
// set方法的形式注入属性值
String methodName="set"+new String(names);
Method method= clazz.getDeclaredMethod(methodName,clazz.getDeclaredField(name).getType());
method.invoke(value,map.get(ref));
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public Object getBean(String key){
return map.get(key);
}
}
Spring IOC工作原理就是将xml文件解析后,获得类全路径,通过反射技术创建对象,然后将对象存到了spring容器里