JavaWeb05Servlet-api与MVC-IOC(对控制反转和依赖注入的初步认识)

servlet-api:(学习一些servlet关于初始化的api):

 之前就说过,HttpServlet的一个父类,GenericServlet里有初始化方法

我们可以看到这两个init基本上没什么内容,我们可以在demo01重写init方法,让我们的代码在初始化的时候就可以完成一些操作,比如初始化的时候给一些参数赋值

 

 问题来了,我使用这个方法,获取到的值应该设置在哪里?

1.通过xml文件配置初始化赋值:

通过<init-param>标签赋值

 此时在之前的方法名中填写hello就可以获得world了

 获取成功

而且可以设置多个键值对标签初始化的时候赋值

2.通过注解初始化赋值:

我们点击@webservlet可以看到里面有个urlpatterns和initparams

 urlpatterns就是之前我们配置文件里的对应关系,也变相说明了,可以多个servlt-mapping对应一个servlet

initparams就可以写我们想要初始化时赋的值

 

同样的我们也可以在初始化的时候获取servletcontext(servlet上下文)的值

1.通过xml文件配置初始化赋值:

 

 

总结:

业务层(service层)引入:

 

 经过对比,我们发现我们的fruit系统还没有业务对象,所以现在我们需要把service层也加入到系统架构中

 现在对于我们的fruit系统现在都有哪些功能?

 

 

 

 

 所以相对应的

接口:

 实现类:

 

 所以现在就是fruitcontroller调用fruitservice,fruitservice调用fruitDAO

所以现在的fruitcontroller就不用new fruitDAO了,需要修改

 

 

 

 

 

测试:一切功能正常,已经完成分层

IOC(实现依赖注入控制反转):

首先,什么样的系统是一个好系统呢?

 我们现在的层与层就是存在依赖的,我们的controller依赖service,servive依赖dao,这样子就不是特别好,我们现在想实现如果把service删除,对controller没有影响,现在是不可能实现的,现在唯一想删除不报错的办法就是设置为null,但是设置为null系统就无法运行。我们的IOC就可以帮我们实现即使设置为null,也可以有我们需要的对象去new和使用

 

ioc是如何操作的?

我们之前使用了配置文件,通过请求的路径获取了对应实例化的对象,如果我们设置一个容器,让我们所有的需要被使用的对象在系统初始化的时候就new好放在容器中,谁使用谁就直接从容器中获取就可以了

编写配置文件:

 专门写一个方法用于获取配置文件对应的实例化对象和id存入Map中(和之前控制器代码类似):

接口:

实现类:

 现在看起来结构就和之前的很相似了,所以我们可以原来获取对应对象的功能直接在这边实现,所以原本控制器里的new Hashmap()和放入容器的代码就不用了

直接剪切放过来

 

 所以现在叫controllerBeanClass就不合适了,现在这个代码适用范围为三层全包

 那之前删除的控制器代码报错,我们就在初始化的时候new classpathxml对象并且调用getBean就好了

 自己的疑问:如果这样子,那我们的io和控制器耦合度不久增高了吗?

如何连接层与层之间的关系?

我们之前已经把new对象设置为null了,层次关系断开了,那我该怎么样让他们使用的时候再次连接起来呢——通过配置文件

已知我们的service需要DAO这个属性

 已知我们的controller需要service这个属性

 我们的配置文件标签<property>就是干这个的

<property>有两个值

name:对应的是当前bean标签对应的对象里,所需要的对象名称

ref:对应的是当前bean容器里引用其他bea的id值

也就是

 

 到现在,service和DAO的依赖关系建立成功

那么同理,controller和service的依赖关系应该为

 现在的ref对应的id应该就是

 设置bean与bean之间的依赖关系:

我们在xml文件里只是描述了bean之间的依赖关系,如何在代码之中设置呢?

我们还可以进行for循环,如果我当前的element的子节点里有<property>就通过它的ref反射对应新的对象

如何判断子节点个数呢?

第一个:

第二个:

 第三个:

该如何获取?

首先获取当前property的name和ref

String propertyName = propertyElement.getAttribute("name");
String propertyRef = propertyElement.getAttribute("ref");

以当前bean标签为

举例

 1.首先找到与当前propertyref对应的实例,也就是fruitserviveimpl

Object refObj = beanMap.get(propertyRef);

2.再找到当前标签对应的实例,也就是fruitcontroller

Object beanObj = beanMap.get(beanId);

3.找到当前beanObj对应的类

Class beanClazz = beanObj.getClass();

4.找到在当前类中与propertyName对应的已经定义好的同名参数,并且设置强制访问

propertyName:

当前类:

当前类中的同名参数: 

Field propertyField = beanClazz.getDeclaredField(propertyName);
                        
propertyField.setAccessible(true);

5.给当前对象(beanObj)设置我们想设置的refObj的值

propertyField.set(beanObj,refObj);

ClassPathXmlApplicationContext完整代码:

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 = DocumentBuilderFactory.newInstance();
            //创建documentBuilder对象
            DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
            //创建document对象
            Document document = documentBuilder.parse(inputStream);



            //利用document对象里的方法获取xml文件里所有bean标签并且生成一个集合
            NodeList beanNodeList = document.getElementsByTagName("bean");
            System.out.println(beanNodeList);
            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);
                    //System.out.println(beanMap);

                    //注意:bean和bean的依赖关系还没有设置
                }
            }
            
            //组装bean之中的依赖关系
            for (int i = 0;i <beanNodeList.getLength();i++) {
                Node beanNode = beanNodeList.item(i);
                if (beanNode.getNodeType() == Node.ELEMENT_NODE) {
                    //拿到当前bean标签
                    Element beanElement = (Element) beanNode;
                    //获取当前bean对象的id
                    String beanId = beanElement.getAttribute("id");
                    //获取当前子节点集合
                    NodeList beanChildNodeList = beanElement.getChildNodes();
                    //对子节点集合进行遍历,如果有property,就对ref和name进行处理
                    for (int j = 0; j < beanChildNodeList.getLength(); j++) {
                        //拿到其中一个结点
                        Node beanChildNode = beanChildNodeList.item(j);
                        //进行判断是不是property
                        if (beanChildNode.getNodeType()==Node.ELEMENT_NODE && "property".equals(beanChildNode.getNodeName())){
                            //如果是property进行强制转换
                            Element propertyElement = (Element) beanChildNode;
                            //取出当前property的name和ref
                            String propertyName = propertyElement.getAttribute("name");
                            String propertyRef = propertyElement.getAttribute("ref");

                            System.out.println(propertyName);
                            System.out.println(propertyRef);
                            //找到propertyRef对应的实例
                            Object refObj = beanMap.get(propertyRef);
                            //把refObj设置到当前bean标签的property的name对应的参数上
                            Object beanObj = beanMap.get(beanId);
                            //找到当前beanObj对应的类
                            Class beanClazz = beanObj.getClass();
                            //找到在当前类中与propertyName对应的已经定义好的同名参数
                            Field propertyField = beanClazz.getDeclaredField(propertyName);
                            //设置强制访问
                            propertyField.setAccessible(true);
                            //给当前对象(beanObj)设置我们想设置的refObj的值
                            propertyField.set(beanObj,refObj);
                        }
                    }



                }
            }


        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SAXException 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) {
        return beanMap.get(id);
    }
}

实现依赖关系为精华

测试:功能一切正常

好耶!!!!!!!!!!!!!!!!!!!!

总结:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值