模拟spring的IoC
1、新建一个web项目,jdk版本为1.8.0_111,使用 Jsp + Servlet + Model 实现MVC模式,并使用BeanFactory工厂 + xml配置文件 + 反射 来解耦合
整个web项目的结构如下图:

1.1、编写BeanFactory工厂
package com.oy; import java.util.HashMap; import java.util.Map; public class BeanFactory { private static BeanFactory beanFactory = new BeanFactory(); // 用于封装bean实例 private Map<String, Object> map = new HashMap<>(); private BeanFactory() {} public static BeanFactory getInstance() { return beanFactory; } /** * 获取参数name指定的实例,而且每次调用返回的是同一个实例。 * @param name * @return */ public Object getBean(String name) { Bean bean = (Bean) map.get(name); if (bean == null) { // System.out.println("map.get(" + name + "),返回null"); return null; } return bean.getBeanInstance(); } /** * 根据类名反射创建一个新的实例 * @param name * @return */ public Object getNewBean(String name) { Bean bean = (Bean) map.get(name); try { return Class.forName(bean.getbeanClassName()).newInstance(); } catch (Exception e) { e.printStackTrace(); } return null; } public void setMap(Map<String, Object> map) { this.map = map; } public Map<String, Object> getMap() { return map; } }
package com.oy; public class Bean { private String beanName; private String beanClassName; private Object beanInstance; public String getBeanName() { return beanName; } public void setBeanName(String beanName) { this.beanName = beanName; } public String getbeanClassName() { return beanClassName; } public void setbeanClassName(String beanClassName) { this.beanClassName = beanClassName; } public Object getBeanInstance() { return beanInstance; } public void setBeanInstance(Object beanInstance) { this.beanInstance = beanInstance; } @Override public String toString() { return "Bean [beanName=" + beanName + ", beanClassName=" + beanClassName + ", beanInstance=" + beanInstance + "]"; } }
1.2、为了在服务器启动时就创建bean实例,写一个监听器 BeanFactoryListener implements ServletContextListener
package com.oy; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; public class BeanFactoryListener implements ServletContextListener { public void contextInitialized(ServletContextEvent sce) { ServletContext sc = sce.getServletContext(); if (sc.getAttribute("beanFactory") != null) { throw new RuntimeException("beanFactory已经存在!"); } BeanFactory beanFactory = BeanFactory.getInstance(); // 把所有bean加载进beanFactory loadBeans(sc, beanFactory); // 把beanFactory添加到ServletContext容器中 // System.out.println("把beanFactory添加到ServletContext容器中"); // System.out.println(beanFactory.getMap()); sc.setAttribute("beanFactory", beanFactory); // System.out.println(sc.getAttribute("beanFactory")); } private void loadBeans(ServletContext sc, BeanFactory beanFactory) { String contextConfigLocation = sc.getInitParameter("contextConfigLocation"); String config = contextConfigLocation.split(":")[1]; InputStream inputStream = BeanFactoryListener.class.getClassLoader().getResourceAsStream(config); SAXReader saxReader = new SAXReader(); try { Document document = saxReader.read(inputStream); Element root = document.getRootElement(); @SuppressWarnings("unchecked") List<Element> list = root.elements(); // 只有map指向beanFactory里面的map,这样每次读一个<bean>就加载一个bean; // 然后,后面加载的bean就可以使用前面已经加载的bean beanFactory.setMap(new HashMap<String, Object>()); Map<String, Object> map = beanFactory.getMap(); Bean bean = null; for (Element e : list) { String beanName = e.attributeValue("id"); String beanClassName = e.attributeValue("class"); bean = new Bean(); bean.setBeanName(beanName); bean.setbeanClassName(beanClassName); bean.setBeanInstance(Class.forName(beanClassName).newInstance()); map.put(beanName, bean); } // 如果等所有bean都添加进map后再把map设置给beanFactory,会造成后面加载的bean无法使用前面加载的bean // beanFactory.setMap(map); } catch (Exception e) { e.printStackTrace(); } } }
1.3、beans.xml文件
<?xml version="1.0" encoding="UTF-8"?> <beans> <bean id="bookDao" class="com.oy.dao.impl.BookDaoImpl"/> <bean id="bookService" class="com.oy.service.impl.BookServiceImpl"/> </beans>
1.4、web.xml文件
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5"> <!-- 监听器:初始化beanFactory --> <listener> <listener-class>com.oy.BeanFactoryListener</listener-class> </listener> <!-- beanFactory的配置文件 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:beans.xml</param-value> </context-param> <servlet> <servlet-name>BookServlet</servlet-name> <servlet-class>com.oy.servlet.BookServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>BookServlet</servlet-name> <url-pattern>/book</url-pattern> </servlet-mapping> </web-app>
2、编写web、service和dao层代码进行测试:
BookServlet类:
package com.oy.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.oy.BeanFactory; import com.oy.entity.Book; import com.oy.service.BookService; public class BookServlet extends HttpServlet { private static final long serialVersionUID = 1L; private BookService bookService = (BookService) BeanFactory.getInstance().getBean("bookService"); public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String method = (String) request.getParameter("method"); if ("add".equals(method)) { add(request, response); } } public void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("调用servlet层的add()方法。。。"); Book book = new Book(); book.setName((String) request.getParameter("name")); bookService.add(book); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
service层接口和实现类:
package com.oy.service; import com.oy.entity.Book; public interface BookService { void add(Book book); }
package com.oy.service.impl; import com.oy.BeanFactory; import com.oy.dao.BookDao; import com.oy.entity.Book; import com.oy.service.BookService; public class BookServiceImpl implements BookService { private BookDao bookDao = (BookDao) BeanFactory.getInstance().getBean("bookDao"); public void add(Book book) { System.out.println("调用service层的add()方法。。。"); if (bookDao != null) { bookDao.add(book); } else { System.out.println("bookDao为null"); } } }
dao层接口和实现类:
package com.oy.dao; import com.oy.entity.Book; public interface BookDao { void add(Book book); }
package com.oy.dao.impl; import java.util.ArrayList; import java.util.List; import com.oy.dao.BookDao; import com.oy.entity.Book; public class BookDaoImpl implements BookDao { private List<Book> bookList = new ArrayList<>(); public void add(Book book) { System.out.println("调用dao层的add()方法。。。"); int size = bookList.size(); book.setId(size + 1); bookList.add(book); System.out.println("bookList: " + bookList); } }
3、项目部署及测试
3.1、服务器:apache-tomcat-9.0.13。
3.2、浏览器输入 http://localhost:8080/05_book/book?method=add&name=张三,回车后,再输入 http://localhost:8080/05_book/book?method=add&name=李四,回车。
控制台打印结果:
调用servlet层的add()方法。。。
调用service层的add()方法。。。
调用dao层的add()方法。。。
bookList: [Book [id=1, name=张三]]
调用servlet层的add()方法。。。
调用service层的add()方法。。。
调用dao层的add()方法。。。
bookList: [Book [id=1, name=张三], Book [id=2, name=李四]]
4、注意事项
根据beans.xml配置文件创建bean实例时,创建顺序是从上到下。如果改变<bean>的顺序,比如像下面这样:
<beans>
<bean id="bookService" class="com.oy.service.impl.BookServiceImpl"/>
<bean id="bookDao" class="com.oy.dao.impl.BookDaoImpl"/>
</beans>
则创建bookService实例时依赖注入失败,因为其依赖一个bookDao实例,但是此时容器中还没有bookDao实例。
posted on 2019-03-13 16:35 wenbin_ouyang 阅读(183) 评论(0) 收藏 举报
浙公网安备 33010602011771号