自己实现简单Spring Ioc
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自己实现简单Spring Ioc相关的知识,希望对你有一定的参考价值。
IoC则是一种 软件设计模式,简单来说Spring通过工厂+反射来实现IoC。
原理简单说明:
其实就是通过解析xml文件,通过反射创建出我们所需要的bean,再将这些bean挨个放到集合中,然后对外提供一个getBean()方法,以便我们获得这bean。
通俗来讲就如同婚姻介绍所,只需要告诉它找个什么样的女朋友,然后婚介就会按照我们的要求,提供一个mm,如果婚介给我们的人选不符合要求,我们就会抛出异常。
简单实现:
1.需要引用maven依赖:
<dependency> <groupId>org.jdom</groupId> <artifactId>jdom</artifactId> <version>1.1.3</version> </dependency>
2.beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="user" class="com.example.domain.User" /> <bean id="userDAO" class="com.example.dao.impl.UserDAOImpl" /> <bean id="userService" class="com.example.service.UserService"> <property name="userDAO" bean="userDAO" /> </bean> </beans>
3.BeanFactory
package com.example.ioc; public interface BeanFactory { Object getBean(String name); }
4.ClassPathXmlApplicationContext:读取xml文件内容,并创建对象及对象关系(使用setter方式)
package com.example.ioc; import org.jdom.Document; import org.jdom.Element; import org.jdom.input.SAXBuilder; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; public class ClassPathXmlApplicationContext implements BeanFactory { private Map<String, Object> beans = new HashMap<String, Object>(); public ClassPathXmlApplicationContext() throws Exception { SAXBuilder sb = new SAXBuilder(); // 构造文档对象 Document doc = sb.build(ClassPathXmlApplicationContext.class .getClassLoader().getResourceAsStream("beans.xml")); // 获取根元素 Element root = doc.getRootElement(); // 取到根元素所有元素 List list = root.getChildren(); setBeans(list); } //设置Bean private void setBeans(List list) throws Exception { for (int i = 0; i < list.size(); i++) { Element element = (Element) list.get(i); String id = element.getAttributeValue("id"); //取得class子元素 String clzss = element.getAttributeValue("class"); //通过反射进行实例化 Object o = Class.forName(clzss).newInstance(); beans.put(id, o); setProperty(element, o); } } //获取property进行依赖注入 private void setProperty(Element element, Object o) throws Exception { for (Element property : (List<Element>) element.getChildren("property")) { String name = property.getAttributeValue("name"); String bean = property.getAttributeValue("bean"); //从beans.xml中根据id取到类的对象 Object beanObj = this.getBean(bean); System.out.println(beanObj);//[email protected] //组成setXXX方法名 String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1); // 反射机制对方法进行调用,将对象在加载bean时就注入到环境上下文中 Method m = o.getClass().getMethod(methodName, beanObj.getClass().getInterfaces()[0]); m.invoke(o, beanObj); } } @Override public Object getBean(String name) { return beans.get(name); } }
以上为核心代码,当然在实际情况中,这一块要复杂的多, 例如:可以一个bean引用另一个bean,还可以有多个配置文件、通过多种方式载入配置文件等等,不过原理还是采用Java的反射机制。
实现的效果为:
Service service=(Service)beans.get("userService");
Dao dao = (Dao)beans.get("userDAO");
//依赖注入,Service实现依赖dao的实现
service.setDao(dao);
5.User:实体类
package com.example.domain; public class User { private String userName; private String password; /** * @return the userName */ public String getUserName() { return userName; } /** * @param userName the userName to set */ public void setUserName(String userName) { this.userName = userName; } /** * @return the password */ public String getPassword() { return password; } /** * @param password the password to set */ public void setPassword(String password) { this.password = password; } public String toString() { StringBuffer sb = new StringBuffer(); sb.append(this.userName); sb.append(this.password); return sb.toString(); } }
6.UserDAO
package com.example.dao; import com.example.domain.User; public interface UserDAO { void save(User u); void delete(); }
7.UserDAOImpl
package com.example.dao.impl; import com.example.dao.UserDAO; import com.example.domain.User; public class UserDAOImpl implements UserDAO { @Override public void save(User u) { System.out.println("User:" + u.toString()); } @Override public void delete() { System.out.println("delete User"); } }
8.UserService
package com.example.service; import com.example.dao.UserDAO; import com.example.domain.User; public class UserService { private UserDAO userDAO; public void addUser(User u) { this.userDAO.save(u); } /** * @return the userDAO */ public UserDAO getUserDAO() { return userDAO; } /** * @param userDAO the userDAO to set */ public void setUserDAO(UserDAO userDAO) { this.userDAO = userDAO; } }
9.测试:
package com.example.ioc; import com.example.domain.User; import com.example.service.UserService; public class RunIoc { public static void main(String[] args) throws Exception { BeanFactory factory = new ClassPathXmlApplicationContext(); //通过工厂直接获取 UserService userService = (UserService) factory.getBean("userService"); //其实User也可以从工厂中获得 User u = (User) factory.getBean("user"); //User u = new User(); u.setUserName("tom"); u.setPassword("123456"); userService.addUser(u);//打印结果tom123456 } }
小结
上文仅仅是简单地模拟了spring的IOC的实现,虽然只是完成了spring中依赖注入的一小部分,但还是很好地展现了Java反射机制在spring中的应用
以上是关于自己实现简单Spring Ioc的主要内容,如果未能解决你的问题,请参考以下文章