Spring IoC容器和bean

2019-07-10  本文已影响0人  夏与清风

IoC容器是spring框架的核心组件,spring通过IoC容器来管理所有Java对象及其相互间的依赖关系。

依赖注入(Dependency Injection,DI)和控制反转的关系:

两者其实是一个事物的两种不同说法,本质上是一回事。依赖注入是一个程序设计模式和架构模型,也称控制反转。在技术上来说依赖注入是一个控制反转的特殊事项,但依赖注入还指一个对象应用另外一个对象来提供一个特殊的能力。如把一个数据库连接以参数的形式传到一个对象的结构方法里,而不是在那个对象内部自行创建一个连接。

依赖注入和控制反转的基本思想是把类的依赖从类内部转到外部以减少依赖。利用控制反转,对象在被创建时,会由一个调控系统统一进行对象实例的隔离,将该对象锁依赖对象的引用通过调控系统传递给它,或者说被注入到对象中。控制反转是关于一个对象如何获取它所依赖对象的引用的过程,这个过程体现为”谁来传递依赖的引用“这个职责的反转。

控制反转的实现类型:依赖注入(Dependency Injection,DI)和依赖查找(Dependency Lookup)。其中依赖注入应用较为广泛,spring就是采用此方式来实现控制反转的。

IoC容器和bean概述

Spring通过IoC容器来管理所有Java对象及其之间的依赖关系。IoC解决了各个对象之间不需要直接关联,而在需要时由IoC容器来管理对象的依赖关系,开发者只需维护相对独立的各个对象代码即可。

IoC是一个过程,即对象定义及其依赖关系,其他与之配合的对象只能通过构造函数、工厂方法参数、从工厂方法构造或返回或在对象实例上设置的属性来定义依赖关系,然后IoC容器在创建bean时会注入这些依赖项。此过程在职责上是反转的,即先把原来代码中需要实现的对象创建、依赖的代码反转给容器来实现和管理,故称为控制反转。

IoC的应用的设计模式:

1)反射:在程序运行状态中根据提供的类路径或类名,通过反射来动态获取该类所有的属性及方法。

2)工厂模式:把IoC容器当做一个工厂,在配置文件或注解中给出定义,然后利用反射技术,根据给出的类名生成相应的对象。对象生成的代码和对象之间的依赖关系在配置 文件中定义,以此实现解耦。

org.springframework.beans和org.springframework.context包是IoC容器的基础,BeanFactory接口提供了能够管理任何类型对象的高级配置机制,ApplicationContext是BeanFactory的子接口,它更易与AOP功能集成,进行消息资源处理、事件发布、作为应用层特定的上下文。

bean是由spring IoC容器进行实例化、组装并管理的对象。它们之间的依赖关系反映在容器使用的配置元数据中。

配置元数据(Configuration Metadata)

配置元数据描述了spring容器在应用程序中是如何提供实例化、配置和组装对象的。配置元数据的几种方式:基于XML方式、基于注解、基于Java的配置。比较流行的是后两种。

\bullet 基于注解的配置:从spring2.5开始引入。

\bullet 基于Java的配置:从spring3.0开始引入。可以使用Java而不是XML文件来定义应用程序类外部的bean。常用的注解有:@Configuration、@Bean、@Import、@DependsOn。

spring配置至少需要一个活多个由容器管理的bean。基于XML的方式,需要用到<beans/>元素内的<bean/>元素来配置bean,在基于Java的配置中,通常在@Configuration注解的类中使用@Bean注解的方法。

XML配置元数据的方式

在XML文件中,id属性用于标识单个bean定义的字符串,它的值是指协作对象,class属性定义bean的类型,使用完全限定的类名。

基于注解的配置元数据方式

实例化容器

spring IoC容器需要在应用启动时进行实例化,在实例化过程中,IoC容器会从外部资源加载配置元数据,提供给ApplicationContext构造函数。

ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"service.xml","dao.xml"}); //从类路径中加载基于XML的配置元数据

当系统较大时,通常会将bean定义分到多个XML中,这样每个XML配置文件可以表示系统中的逻辑层或模块。当某个构造函数需要多个资源位置时,可以使用一个或多个<import/>从另外一个文件加载bean的定义。

使用一个或多个<import/> 引入bean 

使用容器

ApplicationContext是高级工厂的接口,可以维护不同的bean及其依赖项的注册表。其中<T> T getBean(String var1, Class<T> var2)方法可以用于搜索bean实例。

用getBean()方法获取bean实例

正常情况下应用程序不应该使用ApplicationContext中的方法,因为程序代码不需要调用getBean方法,就可以完全不依赖于spring API。如spring与web框架集成,为各种web框架提供了依赖注入,它允许开发者通过元数据声明对特定bean的依赖关系。

bean的命名

每个bean都有一个或多个标识符,这些标识符在托管bean的容器中必须是唯一的。一个bean一般只有一个标识符,如果需要多个标识符,额外的标识符会被当作是别名。

在基于XML的配置元数据中,使用id或name属性来指定bean标识符。id属性允许指定一个id,这些标识符的名称是字母或者包含特殊字符。如果向bean引入其他别名,可以在name属性中指定,用“,”、“;”、空格分隔。在spring3.1之前,id属性被定义为一个xsd:ID类型,限制了可能的字符。之后的版本被定义为一个xsd:string类型。虽然更改了类型,但bean的唯一性仍由容器强制执行。

用户可以不必为bean提供名称或标识符,若没有显示的提供名称或标识符,容器会为其自动生成唯一的名称。如果想通过名称引用该bean,就必须提供一个名称。

在bean的命名时尽量使用Java规范,即bean的名称要遵循以一个小写字母开头的驼峰命名规则,如“userDao”、"indexController"、"userService"等。spring为未命名的组件生成bean名称,同样遵循上述原则。最简单的命名方式就是直接采用类名称并将其首字母改成小写,但当前两个字母都是大写时可以不进行处理,如“URL”类bean的名称仍然不变。这些命名规则定义在java.beans.Introspector.decapitalize方法中。

decapitalize()定义

实例化bean的方式

bean的实例化就是根据配置来创建对象的过程,主要有以下三种方式:

\bullet 通过构造函数实例化

Spring IoC容器可以管理所有想让它管理的类,如POJO、非bean形式的类等。当使用构造方法来创建bean时,对spring来说并无特殊之处。根据所使用的IoC类型,可能需要一个默认(无参)的构造方法。当使用XML配置方式时,可如下配置:

<bean id="myBean" class="com.xxx.service.MyBean" />

\bullet 使用静态工厂方法实例化

当使用静态工厂方法创建bean时,除了指定class属性外,还要通过factory-method属性来指定创建bean实例的工厂方法,spring将调研此方法返回实例对象。其实它和使用普通构造器创建实例并无差别。示例如下:

<bean id="userService" class="com.xxx.service.UserService" />

public class UserService {

    private static UserService service = new UserServiceImpl();

    private UserService() {}

    public static UserService createInstance() {return service;}

}

\bullet 使用工厂实例方法实例化

通过调用工厂实例的非静态方法进行实例化,与通过静态工厂方法实例化类似,使用时class属性设置为空,而factory-method属性必须指定为当前/祖先容器中包含工厂方法的bean的名称,而该工厂bean的工厂方法本身须通过factory-method属性来设定。示例如下:

<!-- 工厂bean,包含createInstance()方法 -->

<bean id="serviceLocator" class="com.xxx.DefaultServiceLocator" >

    <!-- 其他需要注入的依赖项 -->

</bean>

<!-- 通过工厂bean创建的bean -->

<bean id="userService" factory-bean="serviceLocator" 

    factory-method="createUserServiceInstance" />

<bean id="accountService" factory-bean="serviceLocator" 

    factory-method="createAccountServiceInstance" />

public class DefaultServiceLocator {

    private static UserService userService = new UserServiceImpl();

    private static AccountService accService = new AccountServiceImpl();

    private DefaultServiceLocator() {}

    public UserService  createUserServiceInstance() {return userService;}

    public AccountService  createAccountServiceInstance() {return accService;}

}

--参考文献《Srping5开发大全》

上一篇下一篇

猜你喜欢

热点阅读