Spring博大精深,功能非常多。我们这里简单的模拟一下spring的IOC。
先把model,dao,service写出来,写一个最简单的为例。
在model包下定义一个User:
package com.hello.model;
public class User {
private String userId;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
private String userName;
}
在dao包下定义一个UserDAO:
package com.hello.dao;
import com.hello.model.User;
public interface UserDAO {
public void add(User user);
}
在dao.impl包下定义一个UserDAOImpl:
package com.hello.dao.impl;
import com.hello.dao.UserDAO;
import com.hello.model.User;
public class UserDAOImpl implements UserDAO {
@Override
public void add(User user) {
System.out.println("A user added!");
}
}
在service包下定义一个UserService:
package com.hello.service;
import com.hello.model.User;
public interface UserService {
public void add(User user);
}
在service.impl包下定义一个UserServiceImpl:
package com.hello.service.impl;
import com.hello.dao.UserDAO;
import com.hello.model.User;
import com.hello.service.UserService;
public class UserServiceImpl implements UserService {
private UserDAO userDAO;
public UserDAO getUserDAO() {
return userDAO;
}
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
}
@Override
public void add(User user) {
userDAO.add(user);
}
}
注意这个UserServiceImpl里的userDAO属性要提供好get,set方法,因为我们后面要通过反射机制,把dao给set进来。
下面就是重头戏了,我们要模拟spring,自然要写一个ApplicationContext.xml:
<beans>
<bean id="userDAOImpl" class="com.hello.dao.impl.UserDAOImpl" />
<bean id="userServiceImpl" class="com.hello.service.impl.UserServiceImpl">
<property name="userDAO" ref="userDAOImpl"></property>
</bean>
</beans>
再模拟一个BeanFactory:
package com.hello.spring;
public interface BeanFactory {
public Object getBean(String name);
}
再来一个ClassPathXmlApplicationContext,实现BeanFactory接口:
package com.hello.spring;
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 {
// 从配置文件里解析出来的所有的bean都会放在这个容器里
private Map<String, Object> beans = new HashMap<String, Object>();
public ClassPathXmlApplicationContext() throws Exception {
SAXBuilder sb = new SAXBuilder();
// 读取配置文件
Document document = sb.build(this.getClass().getClassLoader().getResourceAsStream("ApplicationContext.xml"));
// 获取跟节点,即beans节点
Element rootElement = document.getRootElement();
// 获取所有的bean节点
List<Element> elementList = rootElement.getChildren("bean");
// 遍历每一个bean节点,把所有的bean都放到beans容器中,并对每一个bean进行自动装配
for (int i = 0; i < elementList.size(); i++) {
// 读取bean节点的id和class属性
Element element = elementList.get(i);
String id = element.getAttributeValue("id");
String clazz = element.getAttributeValue("class");
// 通过反射获取这个class对应的实例
Object o = Class.forName(clazz).newInstance();
// 放入到beans容器中
beans.put(id, o);
// 遍历这个bean中所有的property节点
for (Element propertyElement : element.getChildren("property")) {
// 读取property节点的name属性,这个name就是要注射的bean的名字
String name = propertyElement.getAttributeValue("name");
// 读取property节点的ref属性,这个ref就是在beans容器中的bean的名字
String ref = propertyElement.getAttributeValue("ref");
// 从beans容器中获取到这个ref所对应的bean
Object refBeanObject = beans.get(ref);
// 根据name,构造出set方法的方法名
String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
// 根据方法名和参数获取到set方法
Method m = o.getClass().getMethod(methodName, refBeanObject.getClass().getInterfaces()[0]);
// 调用set方法,进行注射。这样就实现了自动装配
m.invoke(o, refBeanObject);
}
}
}
@Override
public Object getBean(String name) {
return beans.get(name);
}
}
以上已经模拟完成,我们测试一下:
package com.hello.spring;
import com.hello.model.User;
import com.hello.service.UserService;
public class test {
public static void main(String[] args) throws Exception {
BeanFactory beanFactory = new ClassPathXmlApplicationContext();
UserService userService = (UserService) beanFactory.getBean("userServiceImpl");
userService.add(new User());
}
}
运行一下,可以看到控制台输出:
A user added!
到此,我们已经成功的模拟了一个最简单的spring。