简单的说,Spring就是通过工厂+反射将我们的bean放到它的容器中的,当我们想用某个bean的时候,只需要调用getBean("beanID")方法即可。
原理简单说明:
Spring容器的原理,其实就是通过解析xml文件,通过反射创建出我们所需要的bean,再将这些bean挨个放到集合中,然后对外提供一个getBean()方法,以便我们获得这bean。
下面我们来简单实现一个demo
beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="user" class="com.yyb.model.User" /> <bean id="userDAO" class="com.yyb.dao.impl.UserDAOImpl" /> <bean id="userService" class="com.yyb.service.UserService"> <property name="userDAO" bean="userDAO" /> </bean> </beans>
BeanFactory
public interface BeanFactory { Object getBean(String name); }
ClassPathXmlApplicationContext:读取xml文件内容,并创建对象及对象关系(使用setter方式)
package com.yyb.spring; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; import org.jdom.Document; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.input.SAXBuilder; public class ClassPathXmlApplicationContext implements BeanFactory { private Map<String, Object> beans = new HashMap<String, Object>(); public ClassPathXmlApplicationContext() throws JDOMException, IOException, InstantiationException, IllegalAccessException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException { SAXBuilder sb = new SAXBuilder(); // 构造文档对象 Document doc = sb.build(ClassPathXmlApplicationContext.class .getClassLoader().getResourceAsStream("beans.xml")); // 获取根元素 Element root = doc.getRootElement(); // 取到根元素所有元素 List list = root.getChildren(); for (int i = 0; i < list.size(); i++) { Element element = (Element) list.get(i); // 取id子元素 String beanid = element.getAttributeValue("id"); // 取class子元素 String clzss = element.getAttributeValue("class"); // 实例化 Object o = Class.forName(clzss).newInstance(); // 将所有bean放入map中 beans.put(beanid, o); // 获取property 进行依赖注入 for (Element propertyElement : (List<Element>) element .getChildren("property")) { String name = propertyElement.getAttributeValue("name"); System.out.println(name);//userDAO String bean = propertyElement.getAttributeValue("bean"); System.out.println(bean);//userDAO // 从beans.xml中根据id取到类的对象 //Object beanObj = this.getBean(name); // 从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); System.out.println(name.substring(0, 1).toUpperCase());//U System.out.println(name.substring(1));//serDAO System.out.println(methodName);//setUserDAO // 反射机制对方法进行调用,将对象在加载bean时就注入到环境上下文中 Method m = o.getClass().getMethod(methodName, beanObj.getClass().getInterfaces()[0]); System.out.println(o.getClass());//class com.yyb.service.UserService System.out.println(beanObj.getClass().getInterfaces()[0]);//interface com.yyb.dao.UserDAO System.out.println(m);//public void com.yyb.service.UserService.setUserDAO(com.yyb.dao.UserDAO) // 执行注入,相当于执行了一个setXXX(args..)的方法 m.invoke(o, beanObj); } } } @Override public Object getBean(String name) { return beans.get(name); } }
对于以上这段代码实现的效果为:
Service service=(Service)beans.get("userService");
Dao dao = (Dao)beans.get("userDAO");
//依赖注入,Service实现依赖dao的实现
service.setDao(dao);
User:实体类
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(); } }
UserDAO
public interface UserDAO { void save(User u); void delete(); }
UserDAOImpl
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"); } }
UserService
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; } }
下面我们来简单测试一下实现的效果:
Client
public class client { public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException, JDOMException, IOException { BeanFactory factory = new ClassPathXmlApplicationContext(); //通过工厂直接获取 UserService userService = (UserService) factory.getBean("userService"); //其实User也可以从工厂中获得 User u=(User)factory.getBean("user"); //User u = new User(); u.setUserName("yyb"); u.setPassword("1234"); userService.addUser(u);//打印结果yyb1234 } }
当然以上我们是通过setter方法注入,还可以使用构造器注入,也就是在建立对象的时候建立关系(即在UserService的构造函数中添加对userDAO的赋值操作)
总结:
以上通过IOC的一个简要实现实例,模拟了Spring中IOC的实现,虽然只是完成了Spring中依赖注入的一小部分工作,但是很好的展现了Java反射机制在Spring中的应用,能使我们能更好的从原理上了解IOC的实现,也能为我们实现自己的Spring框架提供了方案。
Spring IOC实现原理demo:IOC
时间: 2024-10-29 12:03:15