Spring IOC 学习笔记

1.引言:

    本文是Spring 官方文档的学习总结,详见原文:https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans

   IOC(Inversion of Control)即控制反转,和AOP(Aspect Oriented Programming)面向切面编程是Spring的两大核心功能组件,由于在Spring中,bean的创建和管理是交由Spring IOC container来操作的,而不是bean类本身来控制的,因此这个过程叫做控制反转(IOC),相应的控制管理bean的container(对象)也就被称为IOC container,Spring中IOC是通过Spring IOC container来实现的,主要是用来解决bean的资源管理和依赖注入等问题。下面主要围绕ioc container是如何处理bean资源管理,依赖注入以及循环依赖等问题来讨论。

 

2.Spring IOC Container:

   2.1概述

  如引言所说,IOC Container是用来管理bean和解决依赖注入等问题的。BeanFactory接口提供了管理Bean的操作,是Spring提供的最基础的管理Bean的方法,而ApplicationContext继承于BeanFactory,同时ApplicationContext还提供了更多企业框架上的功能,, 而IOC container可以通过继承BeanFactory或者ApplicationContext等接口来实现Bean的资源管理,在Spring API中org.springframework.beans和org.springframework.context两个包是Spring IOC container的基础,Spring IOC container默认实现了ApplicationContext接口。

ApplicationContext接口提供如下操作:
1. BeanFactory中的一些用来访问Bean的方法,继承自:ListableBeanFactory接口;
2. 通用的文件加载方法,继承自ResourceLoader接口;
3. 向已注册的Listener监听器发布Event事件,继承自:ApplicationEventPublisher接口;
4. 解析消息,支持国际化,继承于MessageResource接口;
5. 继承父级context(一个Web Application有一个全局的Context,每个Servlet都有一个自己独立的child context);

    一个基本的Spring IOC Container功能结构如下:

 

 

 

    2.2加载配置

        Spring IOC container该加载和管理哪些beans是通过读取配置数据来决定的,通常读取配置数据的方式有以下三种:

          1).XML文件

          2).anotations注解(仍需通过少量xml文件来配置支持注解)

          3).java代码(constructor 参数或者setter方法)

        配置数据可以用来注册和配置一些bean的基本信息(beanName,beanClass类型等),另外还可以用来配置bean之间的依赖关系。

        XML方式配置方法如下(一般是应用中每个层或者模块都是一个独立的xml,例如以下的service层和dao层):

          

<!--services.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- services --> <bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl"> <property name="accountDao" ref="accountDao"/> <property name="itemDao" ref="itemDao"/> <!-- additional collaborators and configuration for this bean go here --> </bean> <!-- more bean definitions for services go here --> </beans>

    

<!-- daos.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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="accountDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao"> <!-- additional collaborators and configuration for this bean go here --> </bean> <bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao"> <!-- additional collaborators and configuration for this bean go here --> </bean> <!-- more bean definitions for data access objects go here --> </beans>

    

    然后就可以在代码中通过以下方法来获取到配置好的bean:

    

// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");

// retrieve configured instance
PetStoreService service = context.getBean("petStore", PetStoreService.class);

// use configured instance
List<String> userList = service.getUsernameList();

    通过以上代码可以发现,当xml文件一旦多了,传入构造函数的参数也就多了,Spring提供如下<import />来指定resource属性进行XML文件合并(xml导入):

    

<!--appBeansConfig.xml-->
<
beans> <import resource="services.xml"/> <import resource="resources/messageSource.xml"/> <import resource="/resources/themeSource.xml"/> <bean id="bean1" class="..."/> <bean id="bean2" class="..."/> </beans>

 

    

  通过注解方式的配置方法如下:

  

@Configuration
public class AppConfig {

    @Bean
    public MyService myService() {
        return new MyServiceImpl();
    }
}

    上述代码等同于下面的XML形式配置:

    

<beans>
    <bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>

    

   然后可以通过以下方法来获取bean:

  

public static void main(String[] args) {
    ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
    MyService myService = ctx.getBean(MyService.class);
    myService.doStuff();
}

 

  那么什么是依赖注入呢,即对象A中有一个对象B的引用,那么对象B对于对象A而言就是一个依赖。常见的依赖注入方法如下两个大的方向:

    1.通过构造器来注入依赖(官方推荐方法)。

    2.通过setter方法来注入依赖(可以用来解决循环依赖问题)。

  其中还可以通过一些对象的工厂方法来实现(原理是一样的),关于依赖注入问题后面详细介绍。

   

  未完待续。。。

posted @ 2019-06-21 10:56  Sukrfq  阅读(126)  评论(0)    收藏  举报