Java Spring DI 依赖注入教程

  • 内容
  • 评论
  • 相关

本课程讲一下spring的DI,也就是依赖注入,或者说是控制反转IOC,这概念听起来有点高大上,其实则不然,就是一种设计思想,强调解耦你的application中的各个Component,当然没有耦合的应用是没有的,凡事都有度,技术到了一定高度,对这个度的把控就是见仁见智的事情了。

好了,废话没少说,进入正题,我们以spring实战中的例子为基础:在圣斗士星矢中有个骑士,名字叫星矢(本故事纯属虚构,如有雷同,纯属活该),这厮的任务是保护一个小网红,名字叫麦当娜,好吧,这个美好的故事就这样开始了,座位故事的设计者,我这样实现这个故事。

package com.gaoxueping.knights;
public class DamselRescuingKnight implements Knight {
private RescueDamselQuest quest;
public DamselRescuingKnight() {
this.quest = new RescueDamselQuest();
}
public void embarkOnQuest() {
quest.embark();
}
}

以上我们的例子中,在构造函数中,我们为了让星矢实现营救任务,让他自己去实现RescueDamselQuest的实例,因此有了轻微的耦合,

以上我们费尽心机的说了那么多耦合的不好处(在传统EJB中,这个弊端很明显,当然在spring的压迫下,EJB目前也支持DI),就是为了引出dependency injection,也就是依赖注入,还是以星矢营救麦当娜为例子,试想一下,我们如果让星矢去营救麦当娜,至于在营救的过程中需要什么辅助,我们采用按需供给的方式,他需要什么技能,我们就是提供什么,这样的话,星矢只要安心去营救麦当娜好了,其他的概不关心。好的,我们给出我们全新的星矢

package com.gaoxueping.controller;

public class BraveKnight implements Knight {
    private Quest quest;

    public BraveKnight(Quest quest) {
        this.quest = quest;
    }

    public void embarkOnQuest(){
        quest.embark();
    }

}

从这里可以看出,星矢没有自己创建营救任务的实例,营救任务的实例是在构造器中作为参数传入,这是注入的一种方式,叫构造器注入,重要的是,传入的营救任务类型是Quest,比如在营救道路上杀一头拦路驴,在牢房斩掉一扇门的任务都会实现Quest这个接口,因此星矢可以在胜任各种营救任务。

从以上的类中看出,BraveKnight这个类没有与任何Quest耦合,对星矢来说,他的营救任务只是实现了Quest接口,至于这个探险任务是杀一头驴还是炸一扇门,他不需要关心,这就是DI的好处,松耦合。

例如在星矢在营救任务重要杀一头驴,这个任务可以这样来写

package com.gaoxueping.controller;


public class SlayDragonQuest implements Quest {
    public void embark(){
        System.out.println("Embarking on quest to slay the dragon!");
    }
}

 我们接下来将SlayDragonQuest注入到BraveKnight,也就是装配,可以通过java配置,也可以通过xml,通过java配置如下

package com.gaoxueping.controller;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.gaoxueping.controller.*;


@Configuration
public class KnightConfig {
    @Bean
    public Knight knight(){
        return new BraveKnight(quest());
    }

    @Bean
    public Quest quest(){
        return new SlayDragonQuest();
    }
}

通过xml配置如下

<?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.xsd">

    <bean id="knight_guy" class="com.gaoxueping.controller.BraveKnight">
        <constructor-arg ref="quest" />
    </bean>

    <bean id="quest" class="com.gaoxueping.controller.SlayDragonQuest">
    </bean>

</beans>

然后我们调用一下试试

package com.gaoxueping.controller;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;


@Controller
public class BraveKnightDo {
    @RequestMapping(value = "/knightDo", method = RequestMethod.GET)
    public void knightDo(){
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("META-INF/spring/knight.xml");
        Knight knight = context.getBean(Knight.class);
        knight.embarkOnQuest();
    }
}

okay,成功,就这样子

评论

0条评论

发表评论

电子邮件地址不会被公开。 必填项已用*标注