Spring框架学习记录一:依赖注入

使用spring框架的好处:

1:基于POJO的轻量级和最小侵入编程
2: 通过依赖注入和面向接口实现松耦合
3:基于切面和惯例进行声明式编程
4:通过切面和模板减少样板式代码

具体的例子来体现

  • 本博客的代码默认使用intellij 加maven进行开发,使用maven皆在方便进行jar包管理,只需引入相应的依赖maven便会帮我们自动配置,且示例代码为结合自己所学以及理解,将生活中生动有趣的例子抽象成代码,以助于理解,如有不足的地方还敬请谅解。*参考书目:spring实战[第四版]

       假如我们想定义一名警察叔叔,他能完成抓小偷的任务。那么我们通常情情况下会这样写:

package cn.learningspring;

public class Police {
    private ZhuaxiaotouWork work;
    public Police(){
        this.work=new ZhuaxiaotouWork();       //实例化出一个抓小偷任务
    }                                        //与ZhuaxiaotouWork紧密耦合
    public void Dowork(){
        work.start();
    }
}

       可以看出,警察叔叔在他的构造函数中自行创建了抓小偷任务,这使得警察叔叔紧密的和抓小偷任务耦合到了一起,这极大的限制了警察叔叔的工作能力,比如让警察叔叔去扶老奶奶过马路,他就没法实现了。
       更难受的是,对警察叔叔的测试也很困难,不仅要保证警察叔叔的Dowork方法被调用,还要保证抓小偷工作的start方法被调用。这就非常难受了。
由此我们可以看出,紧密耦合的代码有以下一些缺点:
1.难以测试
2.难以复用
3.难以理解
为了解决这样的问题。spring中提供了优秀的解决方法—依赖注入

依赖注入

依赖注入(Dependency Injection,简称DI)
       简单的来说就是Class A中用到了Class B的对象b,一般情况下,需要在A的代码中显式的new一个B的对象。采用依赖注入技术之后,A的代码只需要定义一个私有的B对象,不需要直接new来获得这个对象,而是通过相关的容器控制程序来将B对象在外部new出来并注入到A类里的引用中。而具体获取的方法、对象被获取时的状态由配置文件(如XML)来指定。
直说概念可能很抽象,我们继续来看代码,还是警察叔叔,这次我们这样写:

package cn.learningspring;

public class Police {
    private Work work;
    public Police(Work work){   //work被注入进来
        this.work=work;       
    }                                    
    public void Dowork(){
        work.start();
    }
}

       这样一来,不同于之前的警察叔叔,现在的警察叔叔没有自行创建任务。而是在他的构造方法中把任务当成是构造器参数传入
这就是依赖注入的方式之一,构造器注入(constructor injection)
       更重要的是传入的工作类型是work,也就是所有的任务都能实现work接口,所以现在的警察叔叔能够响应任何类型的工作。
work接口的代码如下:

package cn.learningspring;
public interface Work {
    public void start();
}

       也就是说,警察叔叔没有和特定的任务进行耦合,只要是实现了work接口的任务,他都能够执行,具体是哪种任务就无关紧要了。这就是DI带来的最大得收益----松耦合。如果一个对象只通过接口(而不是具体实现或者初始化过程)来表明依赖关系,那么这种依赖就能在对象毫不知情的情况下用不同的具体实现进行替换。
       下面对新的警察叔叔进行测试,只需编写一个测试类并mock一个工作给它即可
至于mock的用法这里就不进行讲解。放一个链接可以自己进行阅读:mockito简单教程
       首先在项目的pom.xml文件中引入相应的依赖:

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-all</artifactId>
      <version>1.10.19</version>
      <scope>test</scope>
    </dependency>

不知道依赖怎么写怎么办???没关系,去这儿可以查到maven依赖查询
测试类代码:

import cn.learningspring.Police;
import cn.learningspring.Work;
import static org.mockito.Mockito.*;

import org.junit.Test;
public class PoliceTest {
    @Test
    public void doworktest(){
        Work mockWork =mock(Work.class);
        Police police=new Police(mockWork);
        police.Dowork();
        verify(mockWork,times(1)).start();
    }
}

运行进行测试,代码正常运行,表明警察叔叔方法找到了依赖。
       现在让我们写一个扶老奶奶过马路类如下:

package cn.learningspring;
public class FuLaonainai implements Work{       //实现了work接口
    private int age;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void start() {
        System.out.println("警察叔叔扶"+age+"岁的老奶奶过马路!");
    }
}

扶老奶奶过马路类实现了work接口,而且又增加了一个年龄age变量,那么如何把age还有扶老奶奶过马路类传给警察叔叔呢?
创建应用组件之间协作的行为通常称为装配(wiring) Spring 有多种装配bean的方式,采用XML是很常见的一种装配方式。下面的程序是一个简单的spring配置文件: polic.xml, 该配置文件将police,Fulaonainai装配到了一起。

<bean id="police" class="cn.learningspring.Police">
  <constructor-arg ref="fulaonainai"/>
</bean>
<bean id="fulaonainai" class="cn.learningspring.FuLaonainai">
  <property name="age" value="80"></property></bean>

另外Spring还提供了基于java的配置,这里就不写了我也没具体学,感兴趣的可以自己百度。通过上面的代码就把bean配置好了。下面编写测试类测试一下,代码如下:

import cn.learningspring.Police;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class PoliceTest {
    public static void main(String args[]){  //加载spring上下文
        ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "applicationContext.xml" });
        Police police=context.getBean(Police.class);   //获取policebean
        police.Dowork();                      //执行work方法
    }
}

执行结果如下:
执行结果

成功的将age的值以及fulaonainai方法传递给警察叔叔。需要注意的一点是,在配置时,不同的注入方法写法也不一样,例如age的赋值以及fulaonainai的注入写法不同,具体区别如下:

 constructor-arg:通过构造函数注入。 
   property:通过setter对应的方法注入。
   

这里的测试类基于配置文件创建了spring上下文1 ,随后获取id为police的bean,得到police对象的引用后直接调用dowork方法就可以执行所赋予的任务了。但是这个类不知道警察叔叔执行了什么任务,只有配置文件知道。至此简单的依赖注入就完成了,我们可以利用依赖注入让组件之间保持松散耦合,赋予对象强大的魔力。

生僻词解释

1:spring上下文:
在基于spring的应用中,应用对象生存与spring容器(container)中,spring容器负责创建对象,装配。配置他们并管理他们的整个生命周期,从生存到死亡。下面的链接是对spring容器的讲解,感兴趣的可以翻阅一下。
spring容器

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值