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的更多相关文章

  1. [原]容器学习(一):动手模拟spring的IoC

    介绍 学习经典框架的实现原理以及设计模式在其实际中的运用,是非常有必要的,可以让我们更好进行面向对象. 本篇文章就来模拟Spring的IOC功能,明白原理后,可以更好的使用它,进而为进行面向对象提供一 ...

  2. 容器学习(一):动手模拟spring的IoC

    介绍 学习经典框架的实现原理以及设计模式在事实上际中的运用,是很有必要的,能够让我们更好进行面向对象. 本篇文章就来模拟Spring的IOC功能.明确原理后,能够更好的使用它,进而为进行面向对象提供一 ...

  3. JAVA模拟Spring实现IoC过程(附源码)

    前言:本人大四学生,第一次写博客,如果有写得不好的地方,请大家多多指正 一.IoC(Inversion of Control)反转控制 传统开发都是需要对象就new,但这样做有几个问题: 效率低下,创 ...

  4. 自己动手模拟spring的IOC

    我们这里是模拟spring,主要模拟spring中的IOC功能,所以在此我们一样要在service层中定义dao的实例,当然不用new出来,我们就通过spring的IOC把这里的dao层注入进来.不要 ...

  5. spring的IOC/DI功能实践

    一.写在前面: 做这个Demo主要是为了能够更好的理解Spring的原理,看再多的文章,听再多的讲解最终都最好自己去实现一遍,可以将Spring的功能分块实现,最终自然比较容易将各个功能组合起来. 这 ...

  6. Java-马士兵设计模式学习笔记-工厂模式-用Jdom模拟Spring

    一.概述 1.目标:模拟Spring的Ioc 2.用到的知识点:利用jdom的xpath读取xml文件,反射 二.有如下文件: 1.applicationContext.xml <?xml ve ...

  7. Java反射机制详解(3) -java的反射和代理实现IOC模式 模拟spring

    IOC(Inverse of Control) 可翻译为“控制反转”,但大多数人都习惯将它称为“依赖注入”.在Spring中,通过IOC可以将实现类.参数信息等配置在其对应的配置文件中,那么当 需要更 ...

  8. (反射+内省机制的运用)简单模拟spring IoC容器的操作

    简单模拟spring IoC容器的操作[管理对象的创建.管理对象的依赖关系,例如属性设置] 实体类Hello package com.shan.hello; public class Hello { ...

  9. 尚学堂Spring视频教程(一):模拟Spring

    Spring简单的说就是作为控制反转的容器,看这篇文章前需要先搞懂“控制反转和依赖注入“这个设计模式 我们先来模拟Spring,实现用户添加的功能,新建WEB项目”Spring_0100_Abstra ...

随机推荐

  1. 深度学习课程笔记(八)GAN 公式推导

    深度学习课程笔记(八)GAN 公式推导 2018-07-10  16:15:07

  2. (zhuan) Recurrent Neural Network

    Recurrent Neural Network 2016年07月01日  Deep learning  Deep learning 字数:24235   this blog from: http:/ ...

  3. Sublime text 3 汉化教程

    首先,需要安装Package Control 启动并进入sublime主界面,打开Sublime Text的控制台(快捷键 ctrl + ~) 然后我们到Package Control官方网站,复制s ...

  4. EPPlus实战篇——Excel写入

    .net core 项目 可以向excel写入任何类型(T)的数据,只要T中的field的[Display(Name = "1233", Description = "# ...

  5. Qt5学习记录:QString与int值互相转换

    1)QString转int 直接调用toInt()函数 例: QString str("100"); int tmp = str.toInt(); 或者: bool ok; QSt ...

  6. WebBrowser获取完整COOKIE

    [DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern bool ...

  7. form提交不刷新,不跳转页面

    利用 iframe 标签 ,后台form处理可以返回void <form action="" method="post" target="nm_ ...

  8. Mybatis中sql语句中的in查询,判断null和size为0的情况

    不严谨的写法,可能会报错:in (),这种情况不符合SQL的语法,导致程序报错. 如果简单只做非空判断,这样也有可能会有问题:本来in一个空列表,应该是没有数据才对,却变成了获取全部数据! 所以一个比 ...

  9. tkinter拦截关闭事件

    import tkinter as tk from tkinter import messagebox root = tk.Tk() def on_closing(): if messagebox.a ...

  10. mint 安装过程

    这几天因为各种原因装系统(自己因为双屏不能旋转,输入法界面始终矬,重装2次(应该都是更新内核和更新时包依赖不对的锅,以后屏蔽内核更新和linux-libc-dev这样的更新,要么就新版本出来重装),和 ...