模拟spring之DI

  1. 使用jdom读取配置文件

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;

public class ClassPathXmlApplicationContext implements BeanFactory{
	//使用一个map来保存加入容器的bean
	Map<String, Object> beans = new HashMap<String, Object>();
	
	public ClassPathXmlApplicationContext() throws Exception {
		//jdom解析配置文件的类
		SAXBuilder sb = new SAXBuilder();
		//解析beans.xml返回Document对象
		Document doc = sb.build(this.getClass().getClassLoader().getResourceAsStream("beans.xml"));
		//根据文档对象获取根元素(beans)
		Element root = doc.getRootElement();
		//获取所以beans下的子节点,本例中全是bean
		List<?> list = root.getChildren();
		//挨个遍历子节点
		for (int i = 0; i < list.size(); i++) {
			Element element = (Element) list.get(i);
			//获取属性id
			String id = element.getAttributeValue("id");
			//获取属性class
			String clazz = element.getAttributeValue("class");
			System.out.println(id + "," + clazz);
			//根据clazz实例化一个对应的对象
			Object o = Class.forName(clazz).newInstance();
			//将对象加入容器
			beans.put(id, o);
		}
	}
	
	public Object getBean(String name) {
		return beans.get(name);
	}
}

测试

class UserServiceTest {

	@Test
	void testAdd() throws Exception {
		BeanFactory beanFactory = new ClassPathXmlApplicationContext();
		UserService userService = new UserService();
		UserDao userDao = (UserDao) beanFactory.getBean("u");
		userService.setUserDao(userDao );//若不加此段代码则会报空指针异常
		userService .add(new User());
	}
}

输出

u,dao.impl.UserDaoImpl
userService,service.UserService
user save

但是上面的测试中如果没有userService.setUserDao(userDao );将会报错,出现空指针异常,原因是此时还没有对UserDao进行初始化

自动装配UserDao

上面代码修改如下

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.input.SAXBuilder;

public class ClassPathXmlApplicationContext implements BeanFactory{
	//使用一个map来保存加入容器的bean
	Map<String, Object> beans = new HashMap<String, Object>();
	
	public ClassPathXmlApplicationContext() throws Exception {
		//jdom解析配置文件的类
		SAXBuilder sb = new SAXBuilder();
		//解析beans.xml返回Document对象
		Document doc = sb.build(this.getClass().getClassLoader().getResourceAsStream("beans.xml"));
		//根据文档对象获取根元素(beans)
		Element root = doc.getRootElement();
		//获取所以beans下的子节点,本例中全是bean
		List<?> list = root.getChildren();
		//挨个遍历子节点
		for (int i = 0; i < list.size(); i++) {
			Element element = (Element) list.get(i);
			//获取属性id
			String id = element.getAttributeValue("id");
			//获取属性class
			String clazz = element.getAttributeValue("class");
			System.out.println(id + "," + clazz);
			//根据clazz实例化一个对应的对象
			Object o = Class.forName(clazz).newInstance();
			//将对象加入容器
			beans.put(id, o);
			//解析bean节点的子节点,property节点,每一个property都是当前对象o的一个属性
			for (Element propertyElement : element.getChildren("property")) {
				//获取property的name属性,即该属性的字段
				String name = propertyElement.getAttributeValue("name");
				//获取property的bean属性,即该属性是是什么类型的,用该属性根据容器中的key取出对应的对象
				String bean = propertyElement.getAttributeValue("bean");
				//在容器中取出该bean
				Object beanObject = beans.get(bean);
				//拼接对应的setter方法
				String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
				System.out.println("Method setter:" + methodName);
				//通过放射执行该方法,为当前对象o初始化该属性
				Method m = o.getClass().getMethod(methodName, beanObject.getClass().getInterfaces()[0]);
				m.invoke(o, beanObject);
			}
		}
	}
	
	public Object getBean(String name) {
		return beans.get(name);
	}
}

测试

	@Test
	void testAdd() throws Exception {
		BeanFactory beanFactory = new ClassPathXmlApplicationContext();
		UserService userService = (UserService) beanFactory.getBean("userService");;
		userService .add(new User());
	}

输出

u,dao.impl.UserDaoImpl
userService,service.UserService
Method setter:setUserDao
user save

此时已完成自动装配,没有报错

使用到的文件

  • beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans>

	<bean id="u" class="dao.impl.UserDaoImpl"></bean>
	
	<bean id="userService" class="service.UserService">
		<property name="userDao" bean="u"></property>
	</bean> 
	
</beans>
  • User.java
public class User {
	private String name;
	private String pass;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPass() {
		return pass;
	}
	public void setPass(String pass) {
		this.pass = pass;
	}
	
}
  • UserService.java
public class UserService {

	private UserDao userDao;

	public void add(User u) {
		userDao.save(u);
	}

	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}
}

  • UserDao.java
public interface UserDao {
	
	public void save(User u);
	
}
  • UserDaoImpl.java
public class UserDaoImpl implements UserDao {

	public void save(User u) {
		System.out.println("user save");
	}
}

总结

上面的实验模拟了spring的DI(依赖注入),实现了自动装配,在自动装配的过程中我们并没有直接在测试代码中使用userService.setUserDao(new UserDao())的方式主动去为userService的属性userDao进行初始化,而是交由外部容器BeanFactory帮助我们去实现,实现了控制反转(IOC)。

外部容器BeanFactory内部是通过读取配置文件对其解析,获取到当期对象相应的属性,然后使用反射得出对应的bean和对应的setter方法,通过调用当前对象的setter方法为属性初始化。

DI和IOC为我们简化了对象初始化的细节,即无需关注对象内部属性是否完成初始化,直接使用就好,大大减少了代码量,提高了开发效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值