Spring模拟——BeanFactory 博客分类: JavaEE springBeanFactoryIOC
程序员文章站
2024-02-06 19:30:16
...
续上篇,在解决完配置文件的解析之后,写了一个简单addUser模块准备测试
model代码:
package com.l.model; public class User { private String name; private String password; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
DAO(接口代码未贴出)
package com.l.impl; import com.l.dao.UserDAO; import com.l.model.User; public class UserDAOImpl implements UserDAO { @Override public void save(User u) { System.out.println("Success!"); } }
UserService代码:
package com.l.service;
import com.l.dao.UserDAO;
import com.l.model.User;
public class UserService {
private UserDAO dao;//标红
public UserDAO getUserDAO() {
return dao;
}
public void setUserDAO(UserDAO dao) {
this.dao = dao;
}
public void add(User user) {
dao.save(user);
}
}
下面进行测试:
package com.l.service; import java.io.IOException; import org.junit.Test; import com.l.impl.UserDAOImpl; import com.l.model.User; public class UserServiceTset { @Test public void addTest() throws IOException, Exception{ UserService service = new UserService(); User u = new User(); service.add(u); } }
当你测试完,会报一个空指针错误,这是因为UserService中没有new一个UserDAO对象,这就是spring的好处,不用自己进行手动创建对象。是怎么实现的呢?
在spring中有这样一个配置文件,叫beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="u" class="com.l.impl.UserDAO"> </bean> </beans>
使用上篇的方法对其进行解析
package com.l.spring; import java.io.IOException; 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{ private Map<String, Object> beans = new HashMap<String, Object>(); public ClassPathXMLApplicationContext() throws Exception, IOException{ SAXBuilder builder = new SAXBuilder(); Document doc = builder.build(this.getClass() .getClassLoader().getResourceAsStream("beans.xml")); Element root = doc.getRootElement(); List<Element> elements = root.getChildren("bean"); for (int i = 0; i < elements.size(); i++) { Element element = elements.get(i); String id = element.getAttributeValue("id"); String clazz = element.getAttributeValue("class");//获取UserDAO的类名 System.out.println(id + " : " + clazz); Object o = Class.forName(clazz).newInstance();//为UserDAO创建一个对象 beans.put(id, o); } } @Override //通过getBean获取为UserDAO创建的对象 public Object getBean(String id) { return beans.get(id); } }
通过解析beans.xml中的类名,为其创建对象,实现BeanFactory中的getBea()方法,让外界获取该对象
BeanFactory接口:
package com.l.spring; public interface BeanFactory { public Object getBean(String name); }
再次对其进行测试:
package com.l.service; import java.io.IOException; import org.junit.Test; import com.l.impl.UserDAOImpl; import com.l.model.User; import com.l.spring.BeanFactory; import com.l.spring.ClassPathXMLApplicationContext; public class UserServiceTset { @Test public void addTest() throws IOException, Exception{ BeanFactory factory = new ClassPathXMLApplicationContext(); UserService service = new UserService(); UserDAO userDAO = (UserDAO) factory.getBean("u"); service.setUserDao(userDAO); User u = new User(); u.setName("nimA"); u.setPassword("heh"); service.add(u); } }
通过测试
通过BeanFactory来实例化,管理对象,使用它的实现类ClassPathXmlApplicationContext来新建对象,将配置文件中对应的id和对象放入Map中。
再想一下,既然UserDAO可以这样来实现,那么UserService也是可以的:
在beans.xml中加入再添加一个bean标签<bean id="userService" class="com.l.service.UserService">
测试代码:
package com.l.service; import java.io.IOException; import org.junit.Test; import com.l.impl.UserDAOImpl; import com.l.model.User; import com.l.spring.BeanFactory; import com.l.spring.ClassPathXMLApplicationContext; public class UserServiceTset { @Test public void addTest() throws IOException, Exception{ BeanFactory factory = new ClassPathXMLApplicationContext(); UserDAO userDAO = (UserDAO) factory.getBean("u"); UserService service = (UserService)factory.getBean("userService");//标红 service.setUserDao(userDAO); User u = new User(); service.add(u); } }代码中标红部分, 分两次调用了getBean方法,然而却是没有这个必要的。在bean.xml中<bean>下添加一个子标签<property>
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="u" class="com.l.impl.UserDAOImpl"/> <bean id="userService" class="com.l.service.UserService"> <property name="userDAO" bean="u"/> </bean> </beans>property是告诉你,“userService”中有一个setUserDAO的方法,当调用该方法时,将后面指定的bean传进去,这种方法叫做注入:
注入代码:
List<Element> property = element.getChildren("property"); for(Element propertyElement : property) { String name = propertyElement.getAttributeValue("name"); //userDAO String bean = propertyElement.getAttributeValue("bean"); //u Object beanObject = beans.get(bean);//UserDAOImpl instance String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1); Method m = o.getClass().getMethod(methodName, beanObject.getClass().getInterfaces()[0]); // System.out.println(m.getName()); m.invoke(o, beanObject); }将这段代码加到解析bean.xml的java文件的for循环中,此处用到的是反射机制,通过解析配置文件,Map中存有<"u", 相应对象><"userService", 相应对象>,配置文件中第一个<bean>标签下没有<property>,循环至第二个,即"userService" 取出”userService“中的setUserDAO方法,最后通过invoke(obj,args)实现注入,参数obj为调用该方法的对象(此处为o),参数args为取出方法的参数setUserDAO的参数为为一个UserDAO对象,而beanObject就是该类型。
test代码:
package com.l.service; import java.io.IOException; import org.junit.Test; import com.l.impl.UserDAOImpl; import com.l.model.User; import com.l.spring.BeanFactory; import com.l.spring.ClassPathXMLApplicationContext; public class UserServiceTset { @Test public void addTest() throws IOException, Exception{ BeanFactory factory = new ClassPathXMLApplicationContext(); UserService service = (UserService)factory.getBean("userService"); User u = new User(); service.add(u); } }
测试通过,从原理上了解IOC更好的开始学习spring
推荐阅读
-
Spring模拟——BeanFactory 博客分类: JavaEE springBeanFactoryIOC
-
Spring知识整理(三)—— BeanFactory 博客分类: Spring知识整理 SpringJ2EEJavaBeanFactorySSH
-
spring的beanFactory和factoryBean 博客分类: Java beanFactoryfactoryBeanspringbean
-
spring学习----BeanFactory 博客分类: Spring springBeanFactory
-
二、Spring源码分析——BeanFactory 博客分类: Spring Spring源码分析BeanFactory
-
BeanFactory已被废弃----读取Spring配置文件类 博客分类: Spring SpringBeanFactoryApplicationContextapplicationContext.xml