Spring IOC

1.1      Spring IOC

IOC,全称(Inverse Of Control),中文意思为:控制反转,Spring框架的核心基于控制反转原理。

什么是控制反转?

控制反转是一种将组件依赖关系的创建和管理置于程序外部的技术。

l  由容器控制程序之间的关系,而不是由代码直接控制

l  由于控制权由代码转向了容器,所以称为反转

 

对象与对象之间的关系可以简单的理解为对象之间的依赖关系:

依赖关系:在A类需要类B的一个实例来进行某些操作,比如在类A的方法中需要调用类B的方法来完成功能,叫做A类依赖于B类。

 

一个需要特定的依赖的组件一般会涉及一个依赖对象,在IOC的概念中叫做目标(target)。换句话说,IOC提供了这样的服务,使一个组件能够在它的整个生命周期中访问它的依赖和服务,用这种方法与它的依赖进行交互。总的来说,IOC能够被分解为两种子类型:依赖注入和依赖查找。

 

1.1.1   依赖查找

比如使用JNDI注册一个数据库连接池的示例中,代码中从注册处获得依赖关系的JNDI查找(JNDI lookups)

initContext = new InitialContext();

//获取数据源

DataSource ds = (DataSource) initContext.lookup("java:comp/env/jdbc/mysql");

 

1.1.2   依赖注入

(Dependency Injection)依赖注入:两个对象之间的依赖关系在程序运行时由外部容器动态的注入依赖行为方式称为依赖注入(DI)DIIOC的一种形式。

 

IoC在应用开发中是一个非常有力的概念。如Martin Flower所述,IoC的一种表现形式就是依赖性注射。依赖性注射用的是好莱坞原则,"不要找我,我会找你的。"。换句来说,你的类不会去查找或是实例化它们所依赖的类。控制恰好是反过来的,某种容器会设置这种依赖关系。使用IoC常常使代码更加简洁,并且为相互依赖的类提供一种很好的方法。

 

依赖注入的三种实现类型:接口注入、Setter注入和构造器注入。

1.1.2.1               接口注入(Type1)

public class ClassA {

private InterfaceB clzB;

public void doSomething() {

Ojbect obj =Class.forName(Config.BImplementation).newInstance();

clzB = (InterfaceB)obj;

clzB.doIt()

}

……

}

上面的代码中,ClassA依赖于InterfaceB的实现,如何获得InterfaceB实现类的实例?传统的方法是在代码中创建InterfaceB实现类的实例,并将起赋予clzB

而这样一来,ClassA在编译期即依赖于InterfaceB的实现。为了将调用者与实现者在编译期分离,于是有了上面的代码,我们根据预先在配置文件中设定的实现类的类名(Config.BImplementation),动态加载实现类,并通过InterfaceB强制转型后为ClassA所用。这就是接口注入的一个最原始的雏形。

而对于一个Type1IOC容器而言,加载接口实现并创建其实例的工作由容器完成,见如下代码。

 

public class ClassA {

         private InterfaceB clzB;

                   public Object doSomething(InterfaceB b) {

                   clzB = b;

                   return clzB.doIt();

         }

         ……

}

在运行期,InterfaceB实例将由容器提供。

Type1IOC发展较早(有意或无意),在实际中得到了普遍应用,即使在IOC的概念尚未确立时,这样的方法也已经频繁出现在我们的代码中。

下面的代码大家应该非常熟悉:

public class MyServlet extends HttpServlet {

         public void doGet(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {

                   ……

         }

}

这也是一个Type1 型注入,HttpServletRequestHttpServletResponse实例由Servlet Container在运行期动态注入。

1.1.2.2               Setter(设值)注入(Type2)

各种类型的依赖注入模式中,设值注入模式在实际开发中得到了最广泛的应用。

 

public class ClassA {

private InterfaceB clzB;

public void setClzB(InterfaceB clzB) {

    this. clzB = clzB;

}

……

}

 

详见Hello World程序

1.1.2.3               构造器注入(Type3)

依赖关系是通过类构造函数建立的

容器通过调用类的构造方法将其所需的依赖关系注入其中

 

public class DIByConstructor {

         private final DataSource dataSource;

         public DIByConstructor(DataSource ds) {

                   this.dataSource = ds;

         }

……

}

 

1.1.2.4               三种依赖注入方式的比较

接口注入:

接口注入模式因为历史较为悠久,在很多容器中都已经得到应用。但由于其在灵活性、易用性上不如其他两种注入模式,因而在IOC的专题世界内并不被看好。

 

Setter注入:

l  对于习惯了传统javabean开发的程序员,通过setter方法设定依赖关系更加直观。

l  如果依赖关系较为复杂,那么构造子注入模式的构造函数也会相当庞大,而此时设值注入模式则更为简洁。

l  如果用到了第三方类库,可能要求我们的组件提供一个默认的构造函数,此时构造子注入模式也不适用。

 

构造器注入:

l  在构造期间完成一个完整的、合法的对象。

l  所有依赖关系在构造函数中集中呈现。

l  依赖关系在构造时由容器一次性设定,组件被创建之后一直处于相对“不变”的稳定状态。

l  只有组件的创建者关心其内部依赖关系,对调用者而言,该依赖关系处于“黑盒”之中。

 

总结:

可见,Type3Type2模式各有千秋,而SpringPicoContainer都对Type3Type2类型的依赖注入机制提供了良好支持。这也就为我们提供了更多的选择余地。理论上,以Type3类型为主,辅之以Type2类型机制作为补充,可以达到最好的依赖注入效果,不过对于基于Spring Framework开发的应用而言,Type2使用更加广泛。

 

### Spring IOC 原理及实现 #### 1. 控制反转(IOC)的概念 控制反转(Inversion of Control,简称 IOC)是一种设计思想,旨在将对象的创建和管理从应用程序代码中分离出来。通过 IOC,开发者无需手动管理对象的生命周期和依赖关系,而是由框架负责这些任务。这种思想使得开发者可以专注于业务逻辑的实现,而不需要关心对象之间的交互细节[^1]。 #### 2. 依赖注入(DI) 依赖注入(Dependency Injection,简称 DI)是实现 IOC 的一种方式。DI 的核心在于通过外部配置或注解的方式,将对象的依赖关系注入到目标对象中,而不是由对象自己负责依赖的创建和管理。依赖注入有三种主要形式:构造器注入、Setter 方法注入和字段注入[^4]。 #### 3. Spring IOC 容器的核心接口 Spring 框架提供了两种主要的 IOC 容器接口: - **BeanFactory**:这是 Spring 框架的基础接口,面向 Spring 内部使用。它负责配置、创建和管理 Bean 的生命周期。 - **ApplicationContext**:这是一个更高级的容器接口,面向开发者使用。它扩展了 BeanFactory 的功能,提供了更多的企业级特性,如国际化支持、事件传播等。在实际开发中,通常使用 ApplicationContext 而非 BeanFactory[^2]。 #### 4. Spring IOC 的实现方式 Spring IOC 的实现主要包括以下几个方面: ##### (1) 元数据解析 Spring 使用 XML 文件、Java 注解或 Java 配置类来定义 Bean 的元数据。例如,通过 `<bean>` 标签在 XML 文件中定义 Bean,或者使用 `@Component`、`@Service` 等注解在 Java 类上声明 Bean[^5]。 示例代码(XML 配置): ```xml <bean id="userDao" class="com.mayuanfei.springioc.dao.impl.UserDaoImpl" /> ``` 示例代码(注解配置): ```java @Component public class UserDaoImpl implements UserDao { // 实现方法 } ``` ##### (2) 依赖注入 Spring 通过反射机制解析 Bean 的依赖关系,并将其注入到目标对象中。以下是一个简单的依赖注入示例: 示例代码(字段注入): ```java @Service public class UserService { @Autowired private UserDao userDao; // 自动注入 UserDao } ``` ##### (3) 生命周期管理 Spring 容器会管理 Bean 的整个生命周期,包括初始化、运行时和销毁阶段。开发者可以通过实现特定的接口(如 `InitializingBean` 和 `DisposableBean`)或使用注解(如 `@PostConstruct` 和 `@PreDestroy`)来定制 Bean 的生命周期行为。 示例代码(生命周期管理): ```java @Component public class MyBean { @PostConstruct public void init() { System.out.println("Bean 初始化"); } @PreDestroy public void destroy() { System.out.println("Bean 销毁"); } } ``` ##### (4) 扩展机制 Spring 提供了丰富的扩展点,允许开发者自定义容器的行为。例如,通过实现 `BeanFactoryPostProcessor` 或 `BeanPostProcessor` 接口,可以在 Bean 初始化前后插入自定义逻辑[^4]。 #### 5. Spring IOC 的优势 Spring IOC 的核心优势包括: - **解耦**:对象之间不再直接依赖具体实现,而是通过接口或抽象类进行交互。 - **灵活性**:通过配置文件或注解动态管理 Bean,便于修改和扩展。 - **可维护性**:集中处理对象的创建和依赖关系,降低了代码复杂度。 ### 总结 Spring IOC 是一种通过容器管理对象生命周期和依赖关系的设计模式。其核心原理包括元数据解析、依赖注入、生命周期管理和扩展机制。通过这些机制,Spring 实现了对象控制权的反转,从而提高了系统的解耦性、灵活性和可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值