控制反转的通俗解释

套用好莱坞的一句名言就是:你呆着别动,到时我会找你。
什么意思呢?就好比一个皇帝和太监
有一天皇帝想幸某个美女,于是跟太监说,今夜我要宠幸美女
皇帝往往不会告诉太监,今晚几点会回宫,会回哪张龙床,他只会告诉太监他要哪位美女
其它一切都交由太监去安排,到了晚上皇帝回宫时,自然会有美女出现在皇帝的龙床上
这就是控制反转,而把美女送到皇帝的寝宫里面去就是注射
太监就是是框架里面的注射控制器类BeanFactory,负责找到美女并送到龙床上去
整个后宫可以看成是Spring框架,美女就是Spring控制下的JavaBean
而传统的模式就是一个饥渴男去找小姐出台
找领班,帮助给介绍一个云云,于是领班就开始给他张罗
介绍一个合适的给他,完事后,再把小姐还给领班,下次再来
这个过程中,领班就是查询上下文Context,领班的一个职能就是给客户找到他们所要的小姐
这就是lookup()方法,领班手中的小姐名录就是JNDI//Java Naming and Directory Interface
小姐就是EJB,饥渴男是客户端,青楼是EJB容器
看到区别了么?饥渴男去找小姐出台很麻烦,不仅得找,用完后还得把小姐给还回去
而皇帝爽翻了,什么都不用管,交给太监去处理,控制权转移到太监手中去了
而不是皇帝,必要时候由太监给注射进去就可以了
看到Spring的美妙了吧,Spring还提供了与多个主流框架的支持
可以和其它开源框架集成

 

 

IoC,用白话来讲,就是由容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。这也
就是所谓“控制反转”的概念所在:控制权由应用代码中转到了外部容器,控制权的转移,是所谓反转。
USB接口例子:
笔记本电脑与外围存储设备通过预先指定的一个接口(USB)相连,对于笔记本而言,
只是将用户指定的数据发送到USB接口,而这些数据何去何从,则由当前接入的USB设备决定。在USB
设备加载之前,笔记本不可能预料用户将在USB接口上接入何种设备,只有USB设备接入之后,这种设
备之间的依赖关系才开始形成。
对应上面关于依赖注入机制的描述,在运行时(系统开机,USB 设备加载)由容器(运行在笔记本
中的Windows操作系统)将依赖关系(笔记本依赖USB设备进行数据存取)注入到组件中(Windows
文件访问组件)。
理解:
传统模式中是类和类之间直接调用,所以有很强的耦合度,程序之间的依赖关系比较强,后期维护时牵扯的比较多。
IOC,用配置文件(XML)来描述类与类之间的关系,由容器来管理,降低了程序间的耦合度,程序的修改可以通过简单的配置文件修改来实现

面向切面编程AOP

Aspect Oriented Programming(面向切面编程),可以 通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一 添加功能的一种技术。

 

 

6.2.1   IOC 原理

IoC,直观地讲,就是容器控制程序之间的关系,而非传统实现中,由程序代码直接操控。这也就是所谓“控制反转”的概念所在。控制权由应用代码中转到了外部容器,控制权的转移是所谓反转。IoC还有另外一个名字—“依赖注入Dependency Injection)”。从名字上理解,所谓依赖注入,即组件之间的依赖关系由容器在运行期决定,形象地说,即由容器动态地将某种依赖关系注入到组件之中。

下面通过一个生动形象的例子介绍控制反转

比如,一个女孩希望找到合适的男朋友,如图6-2所示,可以有3种方式,即青梅竹马、亲友介绍、父母包办。

 

1种方式是青梅竹马,如图6-3所示。

通过代码表示如下。

public class Girl {

  void kiss(){

    Boy boy = new Boy();

  }

}

 

2种方式是亲友介绍,如图**所示。

通过代码表示如下。

public class Girl {

  void kiss(){

    Boy boy = BoyFactory.createBoy();

  }

}

3种方式是父母包办,如图6-5所示。

 

通过代码表示如下。

public class Girl {

  void kiss(Boy boy){

    // kiss boy

   boy.kiss();

  }

}

哪一种为控制反转IoC呢?虽然在现实生活中我们都希望青梅竹马,但在Spring世界里,选择的却是父母包办,它就是控制反转,而这里具有控制力的父母,就是Spring所谓的容器概念。

典型的IoC可以如图6-6所示。

 

IoC3种依赖注入类型如下。

1种是通过接口注射,这种方式要求我们的类必须实现容器给定的一个接口,然后容器会利用这个接口给我们这个类注射它所依赖的类。

public class Girl implements Servicable {

  Kissable kissable;

  public void service(ServiceManager mgr) {

    kissable = (Kissable) mgr.lookup("kissable");

  }

  public void kissYourKissable() {

    kissable.kiss();

  }

}

 

<container>

  <component name="kissable" class="Boy">      

    <configuration> … </configuration>

  </component>

  <component name="girl" class="Girl" />

</container>

2种是通过setter方法注射,这种方式也是Spring推荐的方式

public class Girl {

  private Kissable kissable;

  public void setKissable(Kissable kissable) {

    this.kissable = kissable;

  }

  public void kissYourKissable() {

    kissable.kiss();

  }

}

 

<beans>

  <bean id="boy" class="Boy"/>

  <bean id="girl" class="Girl">

    <property name="kissable">

      <ref bean="boy"/>

    </property>

  </bean>

</beans>

3种是通过构造方法注射类,这种方式Spring同样给予了实现,它和通过setter方式一样,都在类里无任何侵入性,但是,不是没有侵入性,只是把侵入性转移了,显然第1种方式要求实现特定的接口,侵入性非常强,不方便以后移植。

public class Girl {

  private Kissable kissable;

  public Girl(Kissable kissable) {

    this.kissable = kissable;

  }

  public void kissYourKissable() {

    kissable.kiss();

  }

}

 

PicoContainer container = new DefaultPicoContainer();

container.registerComponentImplementation(Boy.class);

container.registerComponentImplementation(Girl.class);

Girl girl = (Girl) container.getComponentInstance(Girl.class);

girl.kissYourKissable();

<think>好的,我现在需要回答用户关于Java中依赖注入的概念及原理的问题。首先,我得理解用户的需求,他们可能对依赖注入不太熟悉,需要简明扼要的解释。根据提供的引用内容,引用[1]提到依赖注入是一种设计模式,使代码更灵活、可维护和易扩展。引用[2]和[3]则进一步联系到SpringIOC容器,说明其如何实现控制反转和依赖注入。 我应该先定义什么是依赖注入,然后解释其原理。需要区分依赖注入和控制反转,因为这两个概念常被一起讨论。用户可能对这两者的区别不太清楚,所以需要明确说明:控制反转是更广泛的概念,依赖注入是其实现方式之一。 接下来,要说明依赖注入如何工作,比如容器管理对象的创建和依赖关系,而不是由对象自己创建依赖。可以举一个简单的例子,比如一个Service类依赖Repository类,传统方式是Service内部new一个Repository实例,而依赖注入则是通过构造函数或setter方法从外部传入Repository实例。这样代码更解耦,易于测试和维护。 然后,结合引用中的内容,特别是引用[3]提到的Spring通过配置定义Bean和依赖关系,在容器启动时自动注入。需要提到常见的注入方式,如构造函数注入、setter注入和字段注入,并比较它们的优缺点。 可能还需要提到依赖注入的好处,比如减少耦合,提高可测试性,便于管理对象生命周期等。同时,简要说明Spring框架如何实现IOC容器,比如使用XML配置、注解或Java配置类来定义Bean,容器负责实例化和注入依赖。 需要确保语言通俗易懂,避免过于技术化的术语,但也要准确。可能用户是初学者,所以例子要简单明了。同时,检查是否有遗漏的关键点,比如依赖注入的三种方式,或者与Service Locator模式的区别?不过根据引用内容,可能不需要深入这些细节,保持回答简洁。 最后,生成相关问题,帮助用户进一步学习,比如原理、不同注入方式的比较,与手动注入的对比,以及Spring中的具体实现。确保问题覆盖用户可能感兴趣的后续知识点。</think>### Java 依赖注入的概念及原理 #### 1. **依赖注入的定义** **依赖注入(Dependency Injection, DI)** 是一种设计模式,用于实现对象之间的解耦。其核心思想是:**将对象的依赖关系(即其他对象或服务)从代码内部创建转移到外部注入**。例如,若类 `A` 需要类 `B` 的功能,传统方式可能直接在 `A` 中实例化 `B`,而依赖注入则通过外部(如容器)将 `B` 的实例传递给 `A`,从而实现松耦合[^1][^3]。 #### 2. **依赖注入的原理** - **控制反转IoC)**:依赖注入是控制反转的一种实现方式。IoC 将对象的创建和管理权从开发者转移给容器(如 Spring 框架IoC 容器)。开发者只需定义依赖关系,容器负责实例化对象并注入所需的依赖[^2][^3]。 - **实现方式**: 1. **构造函数注入**:通过构造函数参数传递依赖。 ```java public class UserService { private final UserRepository repository; // 依赖通过构造函数注入 public UserService(UserRepository repository) { this.repository = repository; } } ``` 2. **Setter 方法注入**:通过 setter 方法设置依赖。 ```java public class UserService { private UserRepository repository; // 依赖通过 setter 方法注入 public void setRepository(UserRepository repository) { this.repository = repository; } } ``` 3. **字段注入(基于注解)**:使用注解(如 `@Autowired`)直接标注字段。 ```java public class UserService { @Autowired private UserRepository repository; } ``` #### 3. **依赖注入的优势** - **解耦**:对象不直接依赖具体实现,而是依赖接口,便于替换实现类。 - **可测试性**:通过注入模拟对象(Mock),方便单元测试。 - **可维护性**:依赖关系集中管理,修改时无需修改大量代码[^1]。 #### 4. **Spring 框架中的实现** SpringIoC 容器通过以下方式实现依赖注入: - **配置方式**:XML 文件、Java 注解(如 `@Component`、`@Autowired`)或 Java 配置类。 - **容器启动流程**: 1. 扫描配置,识别需要管理的 Bean(如 `UserService` 和 `UserRepository`)。 2. 根据依赖关系(如构造函数参数或注解),自动创建 Bean 并注入依赖。 --- ###
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值