java web project--learning through building 3

Tue, Jan 12, 2021 3-minute read

a full-stack web application for users to understand java web system

dispatcherServlet 引入

image

servlets

用 dispatcherServelet 控制 controller, 把反射放到父类

核心控制器统一获取参数

springmvc

image

servlets

mvc service 和 dao 详细区分

image

servlets

image

servlets

mvc ioc 耦合问题

+ 耦合/依赖注入

在软件系统中,层与层之间是存在依赖的。我们也称之为耦合。

我们系统架构或者是设计的一个原则是: 高内聚低耦合。

层内部的组成应该是高度聚合的,而层与层之间的关系应该是低耦合的,最理想的情况 0 耦合(就是没有耦合)

public class FruitController {

    private FruitService fruitService = new FruitServiceImpl() ;

    private String update(Integer fid , String fname , Integer price , Integer fcount , String remark ){
    }
  • step 1:

private FruitService fruitService = null ;

  • 解决空指针问题:

1. 配置 3 个 bean,对应 3 个组件

<beans>

    <bean id="fruitDAO" class="com.atguigu.fruit.dao.impl.FruitDAOImpl"/>
    <bean id="fruitService" class="com.atguigu.fruit.service.impl.FruitServiceImpl">
        <!-- property标签用来表示属性;name表示属性名;ref表示引用其他bean的id值-->
        <property name="fruitDAO" ref="fruitDAO"/>
    </bean>
    <bean id="fruit" class="com.atguigu.fruit.controllers.FruitController">
        <property name="fruitService" ref="fruitService"/>
    </bean>
</beans>

2. 配置 bean 工厂,实现根据 id 获得一个类的功能

public interface BeanFactory {
    Object getBean(String id);
}

3. 配置方法实现 bean 工厂

public class ClassPathXmlApplicationContext implements BeanFactory {

    private Map<String,Object> beanMap = new HashMap<>();

    public ClassPathXmlApplicationContext(){
        try {
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream("applicationContext.xml");
            //1.创建DocumentBuilderFactory
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
            //2.创建DocumentBuilder对象
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder() ;
            //3.创建Document对象
            Document document = documentBuilder.parse(inputStream);

            //4.获取所有的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 ;
                    String beanId =  beanElement.getAttribute("id");
                    String className = beanElement.getAttribute("class");
                    Class beanClass = Class.forName(className);
                    //创建bean实例
                    Object beanObj = beanClass.newInstance() ;
                    //将bean实例对象保存到map容器中
                    beanMap.put(beanId , beanObj) ;
                    //到目前为止,此处需要注意的是,bean和bean之间的依赖关系还没有设置
                }
            }
            //5.组装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);
                        }
                    }
                }
            }
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }


    @Override
    public Object getBean(String id) {
        return beanMap.get(id);
    }
}

IOC - 控制反转 / DI - 依赖注入

控制反转

  • 之前在 Servlet 中,我们创建 service 对象 , FruitService fruitService = new FruitServiceImpl(); 这句话如果出现在 servlet 中的某个方法内部,那么这个 fruitService 的作用域(生命周期)应该就是这个方法级别;(需要大量的创建销毁过程)

如果这句话出现在 servlet 的类中,也就是说 fruitService 是一个成员变量,那么这个 fruitService 的作用域(生命周期)应该就是这个 servlet 实例级别 (不需要大量的创建销毁过程,但生命周期扩大,有线程不安全问题)

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

依赖注入

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

  • 之后,我们将代码修改成 FruitService fruitService = null ; 然后,在配置文件中配置:

       <bean id="fruit" class="FruitController">
            <property name="fruitService" ref="fruitService"/>
       </bean>


javaweb1

javaweb2

javaweb4

javaweb5

spring

springmvc