java框架学习日志-2

原创
2018/12/12 00:06
阅读数 46

上篇文章(java框架学习日志-1)虽然跟着写了例子,也理解为什么这么写,但是有个疑问,为什么叫控制反转?控制的是什么?反转又是什么?
控制其实就是控制对象的创建。
反转与正转对应,正转是由程序本身来创建对象,而反转就是程序本身不创建对象。而是被动地接收对象。
上篇文章虽然把对象的创建这一步移至客户端,但是终究还是由程序来创建对象的。Spring提供了一个Ioc容器,可以用它来创建对象,在spring中,所有java类都是资源,所有资源都是Bean,管理这些Bean的就是Spring提供的Ioc容器。
如果不使用Ioc容器去生成对象,那么所有对象都要靠程序本身创建,如果测试人员要测试一个类,就要自己去构建这个类,和这个类所依赖的其他类,但是测试人员对构建对象并不熟悉,而且也会加大工作量。
如果不使用Ioc容器会怎么样呢?举个例子,我们如果要吃饭,那么就要自己煮饭,自己做菜,自己做饮料。这就是主动去创建对象,但是在有了Ioc容器后,Ioc容器就像饭店,我们只需要描述自己需要什么,然后就不用关注做饭的具体过程,然后等饭端上来就好了,这就是被动地接收对象,下面是代码演示。

主动创建对象

首先需要一个锅,然后准备米饭,饮料,肉。

public class Pan {

    /**
     *锅
     * @param rice 加米饭
     * @param juice 喝什么饮料
     * @param meat 吃什么肉
     * @return 成品
     */
    public String cooking(String rice,String juice,String meat){
        String food=rice+"配"+meat+",再喝点"+juice;
        return food;
    }
}

然后是烹饪过程,需要new一个锅,传入米饭等参数的具体值

public class FoodMaker {
    private Pan pan=new Pan();
    private String rice;
    private String juice;
    private String meat;

    public String getRice() {
        return rice;
    }

    public void setRice(String rice) {
        this.rice = rice;
    }

    public String getJuice() {
        return juice;
    }

    public void setJuice(String juice) {
        this.juice = juice;
    }

    public String getMeat() {
        return meat;
    }

    public void setMeat(String meat) {
        this.meat = meat;
    }

    public String makefood(){
        return pan.cooking(rice,juice,meat);
    }
}

最后测试一下

public class Test {
    public static void main(String[] args) {
        FoodMaker foodMaker=new FoodMaker();
        foodMaker.setRice("白米饭");
        foodMaker.setJuice("可乐");
        foodMaker.setMeat("黄焖鸡");
        String food=foodMaker.makefood();
        System.out.println(food);
    }
}


然后用被动创建对象来实现上面的代码。

被动创建对象

在写代码之前需要先导入相关jar包,这个可以去spring官网下载,既然要用bean去管理java类,那么就需要一个bean的xml文件,在src目录下新建xml文件

既然用的别人的东西,那么就需要导入头文件,spring的头文件,模板如下,现在不用管为什么这么写,复制就对了,之前提到过,bean就是java对象,由spring容器来创建和管理,这里的name可以换成id。id是唯一的,name是别名。class就是类的全限定名,包括位置,因为我这里没写包,所以就只是类名。property就是类里的参数,value就是参数的值。在教学视频中bean的name和类名都是hello,后面要用到hello的时候我分不清楚传的到底是哪个,所以这里我就用了不一样的名字。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    <bean name="cooking" class="FoodMaker">
        <property name="rice" value="土豆饭"/>
        <property name="juice" value="红茶"/>
        <property name="meat" value="小炒肉"/>
    </bean>
</beans>

然后就可以测试一下了

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Test {
    public static void main(String[] args) {
        //解析beans.xml文件,生成相应对象,传入bean容器的名字
        ApplicationContext context=new ClassPathXmlApplicationContext("beans.xml");
        FoodMaker foodMaker=(FoodMaker)context.getBean("cooking");//cooking就是FoodMaker的别名
        System.out.println(foodMaker.makefood());
    }
}

结果。注意结果是通过commons logging打印的,这个需要的jar包同样在spring里面。

从结果上来看,两种写法是一样的,但是通过spring来实现代码,就不需要程序来创建对象,对象是由spring容器创建的,对象的属性是由spring容器来设置的。这么一个过程就叫控制反转。这样的话,如果以后需要添加对象,就不用修改代码,可以直接通过bean容器来管理和创建对象,比如再添加一顿饭就可以这样添加。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    <bean name="cooking" class="FoodMaker">
        <property name="rice" value="土豆饭"/>
        <property name="juice" value="红茶"/>
        <property name="meat" value="小炒肉"/>
    </bean>
    <bean name="cooking2" class="FoodMaker">
        <property name="rice" value="炒饭"/>
        <property name="juice" value="肥仔快乐水"/>
        <property name="meat" value="肥仔快乐堡"/>
    </bean>
</beans>

测试结果

控制反转还有个名字叫依赖注入。在上面的例子中,依赖指的是FoodMaker对rice,juice,meat的依赖。而rice等属性的值是由容器给的,这叫依赖注入,其实是一个东西,只是看的角度不一样。

总结

其实ioc是一种编程思想,它的目的也是遵循了设计模式中的降低程序耦合度,方便拓展,避免修改。上面例子中是将对象的创建脱离出程序本身,让spring去完成,其实这只是一方面,主要思想是将主动编程变成被动接受。自己去new对象也是主动编程,接收对象也是接收资源。 Ioc的实现是通过ioc容器实现的,ioc容器就是bean工厂(因为bean可以创建很多对象,而且所以也叫bean工厂。bean工厂其实也是工厂模式,只是这种工厂模式是由spring提供,之前看设计模式,以为这些设计模式都要自己写,原来也有轮子可以用,比如单例模式,只要在beans.xml里的class="FoodMaker"后面加上scope="single"。代码如下

<bean name="cooking" class="FoodMaker" scope="singleton">
        <property name="rice" value="土豆饭"/>
        <property name="juice" value="红茶"/>
        <property name="meat" value="小炒肉"/>
    </bean>

上面的例子其实使用bean来创建对象还不够彻底,在FoodMaker类里面,还有个Pan对象是我们手动创建的。之前在只是简单的给一些String属性赋值,那如果是复杂一点的对象怎么赋值呢?代码如下:
修改在FoodMaker的代码,让pan的值为null,生成set,get方法,通过set,get方法来给pan赋值。

    private Pan pan=null;
    private String rice;
    private String juice;
    private String meat;

    public Pan getPan() {
        return pan;
    }

    public void setPan(Pan pan) {
        this.pan = pan;
    }

beans.xml布置文件如下,其中ref是引用对象,由spring创建。以后如果添加其他烹饪工具,只需要用spring创建对象,然后传入ref就可以了。就不需要改变代码了。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
    <bean id="pan" class="Pan"/>
    <bean name="cooking" class="FoodMaker">
        <property name="rice" value="土豆饭"/>
        <property name="juice" value="红茶"/>
        <property name="meat" value="小炒肉"/>
        <property name="pan" ref="pan"></property>
    </bean>
</beans>

注意!!!

public class FoodMaker {
    private Pan pan=null;//id=“pan”的pan不是这里的pan。
    private String rice;
    private String juice;
    private String meat;

    public Pan getPan() {
        return pan;
    }

    public void setPan(Pan pan) {//注意在beans文件中,id=“pan”中的pan,其实setPan中的Pan首字母小写。
        this.pan = pan;
    }

如果这里setPan改成setPPP,那么beans文件里相应的id也要改成pPP,所以一定要注意书写规范,我在写这个例子的时候,因为写xml文件时不会实时纠错,而系统给的错误信息又太多看不懂,所以排错排了很久,才发现是大小写错了。最后再测试一下这个代码,运行结果和之前一样,就不贴图了。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部