JavaWeb阶段性项目1:Servlet-api、mvc-service引入、IOC和DI

Servlet-api

servlet类的继承与实现结构

  1. Servlet生命周期:实例化、初始化、服务、销毁

init()方法

抽象类GenericServlet实现了Servlet接口中的init方法,初始化Servlet

public void init(ServletConfig config) throws ServletException {
    this.config = config;
    this.init();
}
​
public void init() throws ServletException {
}

我们可以通过在HttpServlet子类中重写init方法在初始化时做一些准备工作通常是使用参数servletconfig来获取配置信息。

public class Demo01Servlet extends HttpServlet {
    @Override
    public void init() throws ServletException {
        ServletConfig config = getServletConfig();
        String initValue = config.getInitParameter("hello");
        System.out.println("initValue = " + initValue);
​
        ServletContext servletContext = getServletContext();
        String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation");
        System.out.println("contextConfigLocation = " + contextConfigLocation);
    }
}

web.xml

也可以通过注解的方式进行配置: @WebServlet(urlPatterns = {"/demo01"} , initParams = { @WebInitParam(name="hello",value="world"), @WebInitParam(name="uname",value="jim") })

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    
    <servlet>
        <servlet-name>Demo01Servlet</servlet-name>
        <servlet-class>com.atguigu.servlet.Demo01Servlet</servlet-class>
        <init-param>
            <param-name>hello</param-name>
            <param-value>world</param-value>
        </init-param>
        <init-param>
            <param-name>uname</param-name>
            <param-value>jim</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>Demo01Servlet</servlet-name>
        <url-pattern>/demo01</url-pattern>
    </servlet-mapping>
    
</web-app>

该方法可以解析web.xml,以此来获取我们初始化设置的数据,将解析的数据放入共享变量中(此知识点在框架技术中有所涉及)

  • 获取config对象:ServletConfig config = getServletConfig();

  • 获取初始化参数值: config.getInitParameter(key);.

ServletContext和<context-param>

ServletContext

保存了共享数据

在服务方法中获取:

@WebServlet("/demo05")
public class Demo05Servlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1.向request保存作用域保存数据
        //Servlet上下文
        ServletContext application = req.getServletContext();
        application.setAttribute("uname","keke");
        //2.客户端重定向
        resp.sendRedirect("demo06");
        /*//服务器内部转发
        req.getRequestDispatcher("demo06").forward(req,resp);*/
    }
}

在初始化方法中获取

ServletContxt servletContext = getServletContext();

获取初始化值: servletContext.getInitParameter();

<context-param>

在web.xml文件中使用<context-param>配置ServletContext的公共初始化参数来创建公共信息

<!-- 配置上下文参数 -->
<context-param>
    <param-name>key</param-name>
    <param-value>value</param-value>
</context-param>

获取初始化值

servletContext.getInitParameter("key");

servletContext.getInitParameter();

mvc-service引入

引入前结构

引入后

service就是多个DAO的组合调用,只不过这里的service比较简单,和普通DAO没有区别

MVC模式

MVC : V:view 视图 ; C:Controller 控制器 ; M:Model 模型 模型有很多种类:数据访问模型(DAO);业务逻辑模型(BO);值对象模型(POJO);数据传输对象(DTO)

package com.fancy.fruit.biz;
​
import com.fancy.fruit.pojo.Fruit;
​
import java.util.List;
​
public interface FruitService {
    //获取指定页面的库存列表信息
    List<Fruit> getFruitList(String keyword, Integer pageNo);
    //添加库存记录信息
    void addFruit(Fruit fruit);
    //根据id查看制定库存记录
    Fruit getFruitByFid(Integer fid);
    //删除特定库存记录
    void delFruit(Integer fid);
    //获取总页数
    Integer getPageCount(String keyword);
    //修改特定库存记录
    void updateFruit(Fruit fruit);
}

注意:运行失败的看看是不是DispatcherServlet运行时把获取的方法参数给自动抹除了

package com.fancy.fruit.biz.impl;
​
import com.fancy.fruit.biz.FruitService;
import com.fancy.fruit.dao.FruitDAO;
import com.fancy.fruit.dao.impl.FruitDAOImpl;
import com.fancy.fruit.pojo.Fruit;
​
import java.util.List;
​
public class FruitServiceImpl implements FruitService {
    private FruitDAO fruitDAO = new FruitDAOImpl();
​
    @Override
    public List<Fruit> getFruitList(String keyword, Integer pageNo) {
        return fruitDAO.getFruitList(keyword, pageNo);
    }
​
    @Override
    public void addFruit(Fruit fruit) {
        fruitDAO.addFruit(fruit);
    }
​
    @Override
    public Fruit getFruitByFid(Integer fid) {
        return fruitDAO.getFruitByFid(fid);
    }
​
    @Override
    public void delFruit(Integer fid) {
        fruitDAO.delFruit(fid);
    }
​
    @Override
    public Integer getPageCount(String keyword) {
        int count = fruitDAO.getFruitCount(keyword);
        int pageCount = (count + 5 - 1) / 5;
        return pageCount;
    }
​
    @Override
    public void updateFruit(Fruit fruit) {
        fruitDAO.updateFruit(fruit);
    }
}

改FruitController

package com.fancy.fruit.controllers;
​
import com.fancy.fruit.dao.FruitDAO;
import com.fancy.fruit.dao.impl.FruitDAOImpl;
import com.fancy.fruit.pojo.Fruit;
import com.fancy.myssm.basedao.myspringmvc.ViewBaseServlet;
import com.fancy.myssm.basedao.util.StringUtil;
​
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
​
​
public class FruitController extends ViewBaseServlet {
​
    private FruitDAO fruitDAO = new FruitDAOImpl();
​
    private String update(Integer fid, String fname, Integer price, Integer fcount, String remark) {
​
        //2.获取参数
​
        //3.执行更新
        fruitDAO.updateFruit(new Fruit(fid, fname, price, fcount, remark));
​
        //4.资源跳转
        //super.processTemplate("index",req,resp);
        //此处需要重定向,目的是重新给IndexServlet发请求,然后覆盖到session中,这样index页面上显示的数据才是最新的
        //resp.sendRedirect("fruit.do");//重定向,重新给fruit.do,给session重新给fruit更改后的数据
        return "redirect:fruit.do";
    }
​
    private String edit(Integer fid, HttpServletRequest req) {
        //HTML是模板,thymeleaf是引擎,我们在servlet中调用了引擎并且给了引擎需要的模板和参数
        if (fid != null) {
            Fruit fruit = fruitDAO.getFruitByFid(fid);
            //获取到fruit对象后将之放置在session作用域
            req.setAttribute("fruit", fruit);
            //thymeleaf的viewBaseServlet中的方法,处理模板数据
            //super.processTemplate("edit",req,resp);
            return "edit";
        }
        return "error";
    }
​
    private String del(Integer fid) {
        if (fid != null) {
            fruitDAO.delFruit(fid);
            return "redirect:fruit.do";
        }
        return "error";
    }
​
    private String add(String fname, Integer price, Integer fcount, String remark) {
​
        Fruit fruit = new Fruit(0, fname, price, fcount, remark);
​
        fruitDAO.addFruit(fruit);
​
        return "redirect:fruit.do";
    }
​
​
    private String index(String oper, String keyword, Integer pageNo, HttpServletRequest req) {
        //添加关键词查询功能
        HttpSession session = req.getSession();
​
        if (pageNo == null) {
            pageNo = 1;
        }
        if (StringUtil.isNotEmpty(oper) && "search".equals(oper)) {
            pageNo = 1;
            if (StringUtil.isEmpty(keyword)) {
                keyword = "";
            }
            session.setAttribute("keyword", keyword);
        } else {
            Object keywordObj = session.getAttribute("keyword");
            if (keywordObj != null) {
                keyword = (String) keywordObj;
            } else {
                keyword = "";
            }
        }
​
        // 重新更新当前页的值
        session.setAttribute("pageNo", pageNo);
​
        FruitDAO fruitDAO = new FruitDAOImpl();
        List<Fruit> fruitList = fruitDAO.getFruitList(keyword, pageNo);
        session.setAttribute("fruitList", fruitList);
​
        //总记录条数
        int fruitCount = fruitDAO.getFruitCount(keyword);
        //总页数
        int pageCount = (fruitCount + 5 - 1) / 5;
        session.setAttribute("pageCount", pageCount);
​
        return "index";
    }
​
}

改之后

package com.fancy.fruit.controllers;
​
import com.fancy.fruit.biz.FruitService;
import com.fancy.fruit.biz.impl.FruitServiceImpl;
import com.fancy.fruit.dao.FruitDAO;
import com.fancy.fruit.dao.impl.FruitDAOImpl;
import com.fancy.fruit.pojo.Fruit;
import com.fancy.myssm.basedao.myspringmvc.ViewBaseServlet;
import com.fancy.myssm.basedao.util.StringUtil;
​
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
​
​
public class FruitController extends ViewBaseServlet {
​
    private FruitService fruitService = new FruitServiceImpl();
​
    private String update(Integer fid, String fname, Integer price, Integer fcount, String remark) {
​
        //2.获取参数
​
        //3.执行更新
        fruitService.updateFruit(new Fruit(fid, fname, price, fcount, remark));
​
        //4.资源跳转
        //super.processTemplate("index",req,resp);
        //此处需要重定向,目的是重新给IndexServlet发请求,然后覆盖到session中,这样index页面上显示的数据才是最新的
        //resp.sendRedirect("fruit.do");//重定向,重新给fruit.do,给session重新给fruit更改后的数据
        return "redirect:fruit.do";
    }
​
    private String edit(Integer fid, HttpServletRequest req) {
        //HTML是模板,thymeleaf是引擎,我们在servlet中调用了引擎并且给了引擎需要的模板和参数
        if (fid != null) {
            Fruit fruit = fruitService.getFruitByFid(fid);
            //获取到fruit对象后将之放置在session作用域
            req.setAttribute("fruit", fruit);
            //thymeleaf的viewBaseServlet中的方法,处理模板数据
            //super.processTemplate("edit",req,resp);
            return "edit";
        }
        return "error";
    }
​
    private String del(Integer fid) {
        if (fid != null) {
            fruitService.delFruit(fid);
            return "redirect:fruit.do";
        }
        return "error";
    }
​
    private String add(String fname, Integer price, Integer fcount, String remark) {
​
        Fruit fruit = new Fruit(0, fname, price, fcount, remark);
​
        fruitService.addFruit(fruit);
​
        return "redirect:fruit.do";
    }
​
​
    private String index(String oper, String keyword, Integer pageNo, HttpServletRequest req) {
        //添加关键词查询功能
        HttpSession session = req.getSession();
​
        if (pageNo == null) {
            pageNo = 1;
        }
        if (StringUtil.isNotEmpty(oper) && "search".equals(oper)) {
            pageNo = 1;
            if (StringUtil.isEmpty(keyword)) {
                keyword = "";
            }
            session.setAttribute("keyword", keyword);
        } else {
            Object keywordObj = session.getAttribute("keyword");
            if (keywordObj != null) {
                keyword = (String) keywordObj;
            } else {
                keyword = "";
            }
        }
​
        // 重新更新当前页的值
        session.setAttribute("pageNo", pageNo);
​
        List<Fruit> fruitList = fruitService.getFruitList(keyword, pageNo);
        session.setAttribute("fruitList", fruitList);
​
        //总记录条数
        int pageCount = fruitService.getPageCount(keyword);
        //总页数
        session.setAttribute("pageCount", pageCount);
​
        return "index";
    }
​
}

为什么引入service

什么是业务层

  1. Model1和Model2 MVC : Model(模型)、View(视图)、Controller(控制器) 视图层:用于做数据展示以及和用户交互的一个界面 控制层:能够接受客户端的请求,具体的业务功能还是需要借助于模型组件来完成 模型层:模型分为很多种:有比较简单的pojo/vo(value object),有业务模型组件,有数据访问层组件

    1. pojo/vo : 值对象

    2. DAO : 数据访问对象

    3. BO : 业务对象

区分业务对象和数据访问对象

1) DAO中的方法都是单精度方法或者称之为细粒度方法。什么叫单精度?一个方法只考虑一个操作,比如添加,那就是insert操作、查询那就是select操作.... 2) BO中的方法属于业务方法,也实际的业务是比较复杂的,因此业务方法的粒度是比较粗的 注册这个功能属于业务功能,也就是说注册这个方法属于业务方法。 那么这个业务方法中包含了多个DAO方法。也就是说注册这个业务功能需要通过多个DAO方法的组合调用,从而完成注册功能的开发。 注册:

  1. 检查用户名是否已经被注册 - DAO中的select操作 向用户表新增一条新用户记录 - DAO中的insert操作

    1. 向用户积分表新增一条记录(新用户默认初始化积分100分) - DAO中的insert操作 向系统消息表新增一条记录(某某某新用户注册了,需要根据通讯录信息向他的联系人推送消息) - DAO中的insert操作

      1. 向系统日志表新增一条记录(某用户在某IP在某年某月某日某时某分某秒某毫秒注册) - DAO中的insert操作 ....

所以我们在库存系统中添加业务层组件FruitService来专门处理复杂的业务,Controller专门用来处理客户端的请求

IOC实现

理解IOC

IOC—Inversion of Control,即“控制反转”,是一种设计思想。

  1. 之前在Servlet中,我们创建service对象 , FruitService fruitService = new FruitServiceImpl(); 这句话如果出现在servlet中的某个方法内部,那么这个fruitService的作用域(生命周期)应该就是这个方法级别; 如果这句话出现在servlet的类中,也就是说fruitService是一个成员变量,那么这个fruitService的作用域(生命周期)应该就是这个servlet实例级别

  2. 之后我们在applicationContext.xml中定义了这个fruitService。然后通过解析XML,产生fruitService实例,存放在beanMap中,这个beanMap在一个BeanFactory中 因此,我们转移(改变)了之前的service实例、dao实例等等他们的生命周期。控制权从程序员转移到BeanFactory。这个现象我们称之为控制反转

在软件系统中,层与层之间是存在依赖的。我们也称之为耦合。 我们系统架构或者是设计的一个原则是: 高内聚低耦合。 层内部的组成应该是高度聚合的,而层与层之间的关系应该是低耦合的,最理想的情况0耦合(就是没有耦合)

public class FruitServiceImpl implements FruitService {
    private FruitDAO fruitDAO = new FruitDAOImpl();
public class FruitController extends ViewBaseServlet {
​
    private FruitService fruitService = new FruitServiceImpl();

所谓的解耦,不是说完全没关系,而是在代码层面解除锁定,打个比方就是用胶水黏在一起,还是像乐高那样拼接,以上代码可以看出我们目前的系统各层之前耦合度较高

实现IOC

①修改配置文件applicationContext

配置好三个bean、对应三个组件,下次在Tomcat启动时,就会将三个组件准备好放置在一个容器里。

<?xml version="1.0" encoding="utf-8" ?>
​
<beans>
    <bean id="fruitDAO" class="com.fancy.fruit.dao.impl.FruitDAOImpl" />
    <bean id="fruitService" class="com.fancy.fruit.service.impl.FruitServiceImpl" />
    <!-- 这个bean标签的作用是将来servletpath中涉及的名字对应的fruit,那么就要FruitController这个类来处理-->
    <bean id="fruit" class="com.fancy.fruit.controllers.FruitController"></bean>
​
</beans>

不光如此,以后添加一些Controller和service只需要到xml里面配置,然后beanfactory就会自动放到map里面

②添加BeanFactory接口

package com.fancy.myssm.io;
​
public interface BeanFactory {
    //根据id获取到某一个bean对象
    Object getBean(String id);
}

③添加ClassPathXmlApplicationContext实现BeanFactory

package com.fancy.myssm.io;
​
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
​
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
​
public class ClassPathXmlApplicationContext implements BeanFactory{
    private Map<String,Object> beanMap = new HashMap<>();
​
    public ClassPathXmlApplicationContext(){
        try {
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            //创建document对象
            Document document = documentBuilder.parse(inputStream);
​
            //获取所有的bean节点
            NodeList beanNodeList = document.getElementsByTagName("bean");
​
            for (int i = 0; i < beanNodeList.getLength(); i++) {
                Node beanNode = beanNodeList.item(i);
                //如果是一个元素节点,就强转为元素节点
                if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element beanElement = (Element) beanNode;
                    //获取了bean中的id属性、class属性
                    String beanId = beanElement.getAttribute("id");
                    String className = beanElement.getAttribute("class");
                    //获取全类名后,要获取它的实例对象
                    Class beanClass = Class.forName(className);
                    Object beanObj = beanClass.newInstance();
​
                    //将beanId、beanObj放入Map中
                    beanMap.put(beanId, beanObj);
                }
            }
            for(int i = 0 ; i<beanNodeList.getLength() ; i++){
                Node beanNode = beanNodeList.item(i);
                if(beanNode.getNodeType() == Node.ELEMENT_NODE) {
                    Element beanElement = (Element) beanNode;
                    String beanId = beanElement.getAttribute("id");
                    NodeList beanChildNodeList = beanElement.getChildNodes();
                    for (int j = 0; j < beanChildNodeList.getLength() ; j++) {
                        Node beanChildNode = beanChildNodeList.item(j);
                        if(beanChildNode.getNodeType()==Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())){
                            Element propertyElement = (Element) beanChildNode;
                            String propertyName = propertyElement.getAttribute("name");
                            String propertyRef = propertyElement.getAttribute("ref");
                            //1) 找到propertyRef对应的实例
                            Object refObj = beanMap.get(propertyRef);
                            //2) 将refObj设置到当前bean对应的实例的property属性上去
                            Object beanObj = beanMap.get(beanId);
                            Class beanClazz = beanObj.getClass();
                            Field propertyField = beanClazz.getDeclaredField(propertyName);
                            propertyField.setAccessible(true);
                            propertyField.set(beanObj,refObj);
                        }
                    }
                }
            }
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
    @Override
    public Object getBean(String id) {
        //根据id获取到beanMap容器中某一个bean对象
        return beanMap.get(id);
    }
}

④改原先在DispatcherServlet的init方法中的获取对应Controller的方法体

try {
    InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
    DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
    //创建document对象
    Document document = documentBuilder.parse(inputStream);
​
    //获取所有的bean节点
    NodeList beanNodeList = document.getElementsByTagName("bean");
​
    for (int i = 0; i < beanNodeList.getLength(); i++) {
        Node beanNode = beanNodeList.item(i);
        //如果是一个元素节点,就强转为元素节点
        if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
            Element beanElement = (Element) beanNode;
            //获取了bean中的id属性、class属性
            String beanId = beanElement.getAttribute("id");
            String className = beanElement.getAttribute("class");
            //获取全类名后,要获取它的实例对象
            Class controllerBeanClass = Class.forName(className);
            Object beanObj = controllerBeanClass.newInstance();
​
            //将beanId、beanObj放入Map中
            beanMap.put(beanId, beanObj);
        }
    }
} catch (ParserConfigurationException e) {
    e.printStackTrace();
} catch (SAXException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
} catch (InstantiationException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}

获取全类名后,要获取它的实例对象不再只是对应的Controller,而是三个模型controller、service、DAO

添加到ClassPathXmlApplicationContext构造器中

⑤修改中央控制器DispatcherServlet中的代码

@WebServlet("*.do")
public class DispatcherServlet extends ViewBaseServlet {
​
    private BeanFactory beanFactory ;⭕⭕⭕
​
    //servlet有加载-实例化-服务-销毁的生命周期,所以先在实例化阶段的构造器中解析xml配置文件
    public DispatcherServlet() {
​
    }
​
    //应该使用init方法加载而不是构造器
    public void init() throws ServletException {
        super.init();
        beanFactory = new ClassPathXmlApplicationContext();⭕⭕⭕
    }
​
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
​
        String servletPath = req.getServletPath();
        servletPath = servletPath.substring(1);
        int lastDotIndex = servletPath.lastIndexOf(".do");
        servletPath = servletPath.substring(0, lastDotIndex);
​
        Object controllerBeanObj = beanFactory⭕⭕⭕.getBean(servletPath);
​
        String operate = req.getParameter("operate");

思考:此处为什么声明的是一个接口BeanFactory类型的变量?为什么new 一个ClassPathXmlApplicationContext?

可能是使用多态,增加了代码的可扩展性。new一个ClassPathXmlApplicationContext就可以使用ClassPathXmlApplicationContext中实现的getBean的具体方法(根据id获取到beanMap容器中某一个bean对象),new一个别的实现了BeanFactory接口的类就可以实现其它类的方法,就可以很方便地调用不同的方法获得bean对象。

相反如果此处直接定义一个ClassPathXmlApplicationContext类型的变量,之后调用其它实现了BeanFactory接口的对象中的方法时就要重新改这个定义的变量了。

⑥去掉FruitServiceImpl和FruitController中的耦合

import com.fancy.fruit.service.FruitService;
import com.fancy.fruit.service.impl.FruitServiceImpl;
import com.fancy.fruit.pojo.Fruit;
import com.fancy.myssm.myspringmvc.ViewBaseServlet;
import com.fancy.myssm.util.StringUtil;
​
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.List;
​
​
public class FruitController {
​
    private FruitService fruitService = null;
import com.fancy.fruit.service.FruitService;
import com.fancy.fruit.dao.FruitDAO;
import com.fancy.fruit.pojo.Fruit;
​
import java.util.List;
​
public class FruitServiceImpl implements FruitService {
    private FruitDAO fruitDAO = null;

所以,接下来我们不仅要描述DispatcherServlet需要哪些组件,还需要说明组件与组件之间的依赖关系

fruitservice需要fruitDAO组件,FruitController需要fruitService组件(依赖注入?)

<?xml version="1.0" encoding="utf-8" ?>
​
<beans>
    <bean id="fruitDAO" class="com.fancy.fruit.dao.impl.FruitDAOImpl" />
    <bean id="fruitService" class="com.fancy.fruit.service.impl.FruitServiceImpl" >
        <!-- property标签用来表示属性;name表示属性名;ref表示引用其他bean的id值-->
        <property name="fruitDAO" ref="fruitDAO"/>
    </bean>
    <!-- 这个bean标签的作用是将来servletpath中涉及的名字对应的fruit,那么就要FruitController这个类来处理-->
    <bean id="fruit" class="com.fancy.fruit.controllers.FruitController">
        <property name="fruitService" ref="fruitService"/>
    </bean>
</beans>

此XML文件不仅描述了需要几个bean,还描述了他们之间依赖关系

*框架是通过dom 4j解析成beanDefinition然后挨个循环遍历创建对象,放进名为singObjects的map里

⑦改ClassPathXmlApplicationContext的构造器

之前只向map容器中保存了bean,还没有保存他们之间依赖关系

for(int i = 0 ; i<beanNodeList.getLength() ; i++){
    Node beanNode = beanNodeList.item(i);
    if(beanNode.getNodeType() == Node.ELEMENT_NODE) {
        Element beanElement = (Element) beanNode;
        String beanId = beanElement.getAttribute("id");
        NodeList beanChildNodeList = beanElement.getChildNodes();
        for (int j = 0; j < beanChildNodeList.getLength() ; j++) {
            Node beanChildNode = beanChildNodeList.item(j);
            if(beanChildNode.getNodeType()==Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())){
                Element propertyElement = (Element) beanChildNode;
                String propertyName = propertyElement.getAttribute("name");
                String propertyRef = propertyElement.getAttribute("ref");
                //1) 找到propertyRef对应的实例
                Object refObj = beanMap.get(propertyRef);
                //2) 将refObj设置到当前bean对应的实例的property属性上去
                Object beanObj = beanMap.get(beanId);
                Class beanClazz = beanObj.getClass();
                Field propertyField = beanClazz.getDeclaredField(propertyName);
                propertyField.setAccessible(true);
                propertyField.set(beanObj,refObj);
            }
        }
    }
}
Node 节点
    Element 元素节点
    Text 文本节点
<sname>jim</sname>

 

视频48可以之后学了spring再过来听一遍

DI - 依赖注入

依赖注入:

  1. 之前我们在控制层出现代码:FruitService fruitService = new FruitServiceImpl(); 那么,控制层和service层存在耦合。

  2. 之后,我们将代码修改成FruitService fruitService = null ; 然后,在配置文件中配置: <bean id="fruit" class="FruitController"> <property name="fruitService" ref="fruitService"/> </bean>

posted @ 2022-08-14 01:14  Fancy[love]  阅读(93)  评论(0编辑  收藏  举报