模拟了spring容器的依赖注入,其实spring内部也是通过反射机制来实现的控制反转。主要是看下spring包下的ClassPathXmlApplicationContext类的实现。
完整代码如下:
package com.bjsxt.model;
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.bjsxt.dao;
import com.bjsxt.model.User;
//设计这个接口,是为了更灵活,因此不同的数据库产品,实现方式不一样
//为了可扩展,把这里设计成接口
public interface UserDao {
public void save(User u);
}
package com.bjsxt.dao.impl;
import com.bjsxt.dao.UserDao;
import com.bjsxt.model.User;
public class UserDaoImpl implements UserDao {
public void save(User u) {
System.out.println("a user is save.");
}
}
package com.bjsxt.service;
import com.bjsxt.dao.UserDao;
import com.bjsxt.model.User;
public class UserService {
//这里我定义成接口类型,这样,我想用哪种数据库产品的实现
//我就new哪种,比如userDao = new UserDaoImpl(),如果我想换
//其它的实现,就更改下那句话就行,要是放在配置文件里,就只需更改配置文件
//这就是面向接口的编程
private UserDao userDao;
public UserDao getUserDao() {
return userDao;
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void save(User u){
userDao.save(u);
}
}
package spring;
public interface BeanFactory {
Object getBean(String id);
}
package spring;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import com.bjsxt.dao.UserDao;
public class ClassPathXmlApplicationContext implements BeanFactory{
private Map<String,Object> beans = new HashMap<String,Object>();
public ClassPathXmlApplicationContext() throws JDOMException, IOException{
SAXBuilder sb = new SAXBuilder();
Document doc = sb.build(ClassPathXmlApplicationContext.class
.getClassLoader().getResourceAsStream("beans.xml"));
Element root = doc.getRootElement();
List list = root.getChildren("bean");
for(int i=0;i<list.size();i++){
Element element = (Element) list.get(i);
String id = element.getAttributeValue("id");
String clazz = element.getAttributeValue("class");
Object o = null;
try {
//利用反射机制,根据完整的包名+类名,new出实例
o = Class.forName(clazz).newInstance();
beans.put(id, o);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
List elements = element.getChildren("property");
for(int j=0;j<elements.size();j++){
Element ele = (Element) elements.get(j);
String name = ele.getAttributeValue("name");//userDao
String bean = ele.getAttributeValue("bean");//u
Object beanObject = beans.get(bean);//userDaoImpl instance
//其实就相当于找方法名setUserDao;
String methodName = "set"+name.substring(0,1).toUpperCase()+name.substring(1);
try {
//根据反射机制,执行set方法,这里,先找到方法名,
//根据方法名和方法参数拿到method
// 比如,public void setUserDao(UserDao userDao),这里的方法参数userDao它实现了
//一个接口,所以数组下标为0,所以
//这样就完成了注入
Method m = o.getClass().getMethod(methodName, beanObject.getClass().getInterfaces()[0]);
m.invoke(o, beanObject);
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public Object getBean(String id) {
return beans.get(id);
}
}
beans.xml
<beans>
<bean id="u" class="com.bjsxt.dao.impl.UserDaoImpl" />
<bean id="userService" class="com.bjsxt.service.UserService" >
<property name="userDao" bean="u"/>
</bean>
</beans>
测试代码如下:
package com.bjsxt.service;
import static org.junit.Assert.*;
import java.io.IOException;
import org.jdom.JDOMException;
import org.junit.Test;
import spring.ClassPathXmlApplicationContext;
import com.bjsxt.model.User;
public class UserServiceTest {
//junit4的特点就是不用显示继承TestCase,只要在那个方法前加上注解@Test
public void testSave() {
ClassPathXmlApplicationContext context = null;
try {
context = new ClassPathXmlApplicationContext();
} catch (JDOMException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
UserService us = (UserService) context.getBean("userService");
User u = new User();
us.save(u);
}
}