模拟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实例。
模拟spring的IoC的更多相关文章
- [原]容器学习(一):动手模拟spring的IoC
介绍 学习经典框架的实现原理以及设计模式在其实际中的运用,是非常有必要的,可以让我们更好进行面向对象. 本篇文章就来模拟Spring的IOC功能,明白原理后,可以更好的使用它,进而为进行面向对象提供一 ...
- 容器学习(一):动手模拟spring的IoC
介绍 学习经典框架的实现原理以及设计模式在事实上际中的运用,是很有必要的,能够让我们更好进行面向对象. 本篇文章就来模拟Spring的IOC功能.明确原理后,能够更好的使用它,进而为进行面向对象提供一 ...
- JAVA模拟Spring实现IoC过程(附源码)
前言:本人大四学生,第一次写博客,如果有写得不好的地方,请大家多多指正 一.IoC(Inversion of Control)反转控制 传统开发都是需要对象就new,但这样做有几个问题: 效率低下,创 ...
- 自己动手模拟spring的IOC
我们这里是模拟spring,主要模拟spring中的IOC功能,所以在此我们一样要在service层中定义dao的实例,当然不用new出来,我们就通过spring的IOC把这里的dao层注入进来.不要 ...
- spring的IOC/DI功能实践
一.写在前面: 做这个Demo主要是为了能够更好的理解Spring的原理,看再多的文章,听再多的讲解最终都最好自己去实现一遍,可以将Spring的功能分块实现,最终自然比较容易将各个功能组合起来. 这 ...
- Java-马士兵设计模式学习笔记-工厂模式-用Jdom模拟Spring
一.概述 1.目标:模拟Spring的Ioc 2.用到的知识点:利用jdom的xpath读取xml文件,反射 二.有如下文件: 1.applicationContext.xml <?xml ve ...
- Java反射机制详解(3) -java的反射和代理实现IOC模式 模拟spring
IOC(Inverse of Control) 可翻译为“控制反转”,但大多数人都习惯将它称为“依赖注入”.在Spring中,通过IOC可以将实现类.参数信息等配置在其对应的配置文件中,那么当 需要更 ...
- (反射+内省机制的运用)简单模拟spring IoC容器的操作
简单模拟spring IoC容器的操作[管理对象的创建.管理对象的依赖关系,例如属性设置] 实体类Hello package com.shan.hello; public class Hello { ...
- 尚学堂Spring视频教程(一):模拟Spring
Spring简单的说就是作为控制反转的容器,看这篇文章前需要先搞懂“控制反转和依赖注入“这个设计模式 我们先来模拟Spring,实现用户添加的功能,新建WEB项目”Spring_0100_Abstra ...
随机推荐
- JQ插入节点方法
1.append() appendTo() prepend() prependTo() 2. before() insertBefore() after() insertAfter()
- BZOJ4018: 小Q的幻想之乡
Description 背景 有一天,小Q梦见自己来到了理想国的幻想之乡. 描述 有一天,小Q梦见自己来到了理想国的幻想之乡.幻想乡有无穷户居民,第i个家庭住在编号为i的房屋里,编号从1开始,到正无穷 ...
- 配置和运行 MatchNet CVPR 2015 MatchNet: Unifying Feature and Metric Learning for Patch-Based Matching
配置和运行 MatchNet CVPR 2015 GitHub: https://github.com/hanxf/matchnet 最近一个同学在配置,测试这个网络,但是总是遇到各种问题. 我也尝试 ...
- (转载)winform图片标尺控件
最近要做个winform的东西,要在里面集成一个类似Windows自带画图的标尺功能,还要能在图片上画矩形框.在网上找了好久也没找到写好的控件,无奈自己做了一个. 目前还有些bug,这里先做个分享.( ...
- CIFAR-10与ImageNet图像识别
2.1.2 下载CIFAR-10 数据 python cifar10_download.py # Copyright 2015 The TensorFlow Authors. All Rights R ...
- yyyy-MM-dd'T'HH:mm:ss.SSS'Z'即UTC时间,与String日期转换
本文为博主原创,未经允许不得转载: 最近在使用一个时间插件的时候,接收到的时间格式是 ’2017-11-27T03:16:03.944Z’ ,当我进行双向数据绑定的时候,由后台传过来的时间绑定到时间 ...
- react native 渐变组件 react-native-linear-gradient
github: https://github.com/react-native-community/react-native-linear-gradient 安装:yarn add react-n ...
- _event_team
EventId 事件ID TeamId 事件玩家分组,仅传送(0为联盟 1为部落)对线(防守为1,进攻为2),自定义阵营(_faction表自定义阵营ID),公会(公会guid) TeamName 事 ...
- JAVA关于泛型的笔记
1.Java SE 5.0中增加泛型机制的主要原因是为了满足在1999年制定的最早的Java规范需求之一(JSR 14). 2.使用泛型机制编写的程序代码要比那些杂乱的使用Object变量,然后再进行 ...
- 【C#】采用OleDB读取Excel文件转DataTable
using System; using System.Data; using System.Data.OleDb; using System.IO; using System.Linq; using ...