容器、Bean
-
介绍
IoC(IoCInversion of Control)也叫依赖注入DI(dependency injection)
对象可以通过构造函数参数、工厂方法参数,或者是对象自己被实例化后设置的属性来定义它们所依赖的其它对象。当所依赖的对象被实例化后,容器注入这些bean。bean自己控制依赖的实例化,或者是直接通过类的解析和
Service Locator模式这样的机制来自己决定自己的依赖,这个过程就是IoC。使用IoC容器,需要用到
org.springframework.beans和org.springframework.context两个包BeanFactroy接口提供了一个先进的配置机制,使得容器可以管理任何类型的对象。ApplicationContext是BeanFactroy的子接口,它加入了一下功能:- 与Spring AOP特性的组合更加容易
- 消息资源处理(在网络化时使用)
- 事件发布
- 如在web应用中使用的
WebApplicationContext这样的应用层特殊上下文
总之,
BeanFactroy提供了配置框架和基本的功能,ApplicationContext增加了企业级应用特有的功能。在Spring中,对象被称之为
Bean,一个Bean就是被实例化的被组装的且被Spring IoC容器管理的众多对象中的一个。bean以及bean之间的依赖关系,在容器使用的配置元数据上反应出来。 -
IoC 容器
org.springframework.context.ApplicationContext定义了IoC容器,也负责bean的实例化、配置以及装配。容器通过读取配置元数据来获取实例化、配置合装配bean的指令。配置元数据可以通过XML,java注解以及java代码进行描述。通过配置元数据来描述构成应用的对象以及这些对象之间丰富的内在依赖。
高度抽象的描述Spring如何工作:
在
ApplicationContext被创建和初始化后,使用应用程序的类文件+配置文件形成完全配置化的可运行的程序
How Spring Work2.1 配置元数据
我们通过配置元数据来告诉Spring容器如何在应用中初始化、配置合组织对象。
在基于XML的元数据中,我们使用
<bean>标签来配置一个对象,这些<bean>标签被包含在一个<beans>父标签中。一个简单的基于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="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <!-- more bean definitions go here --> </beans>id:对象的唯一标识符;class:使用类的限定类名(带包名)定义bean的类型 -
实例化容器
提供给
ApplicationContext构造器的路径是一个资源字符串,这些字符串使得容器从不同的外部资源中加载配置元数据。例如从本地文件系统或者CLASSPATH加载配置元数据。//加载在CLASSPATH路径下的service.xml和dao.xml配置元数据来初始化上下文。 ApplicationContext context = ClassPathXmlApplicationContext("service.xml","dao.xml");service.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>dao.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>service层由
PetStoreServiceImpl类和两个数据访问类JpaAccountDao和JpaItemDao组成,元素property name参考PetStoreServiceImpl类域的名字,ref参考对应bean的id。id与ref元素之间的链接描述了合作对象之间的依赖关系。 -
组织基于XML的配置元数据
按照不同的逻辑层或者按应用模块将bean的定义分布在不同的xml文件中是非常有用的。
我们可以使用应用上下文构造器从分散的XML配置文件中加载配置信息。如下所示:
<beans> <import resource="service.xml"/> <import resource="resources/message.xml"/> <import resource="/resources/themeSource.xml"/> <bean id="bean1" class="..."/> <bean id="bean2" class="..."/> </beans>上述配置加载了三个xml配置文件,其路径都是相对路径,即使第三个资源的路径前有一个
/,这个/也会被忽略。不建议使用
../这样的相对路径来引用父路径文件,并且classpath:URLs(如:classpath:../services.xml)也不建议这样的引用。我们可以使用绝对路径来引用配置文件,如:file:c:/config/service.xml或者classpath:/config/service.xml -
使用容器
ApplicationContext是一个接口,使得实现它的工厂类拥有各种bean及其依赖bean的注册表。通过调用T getBean(String name, Class<T> requeredType),我们得到需要的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();GenericApplicationContext与加载器的组合灵活多变的,如我们可以使用XmlBeanDefinitionReader来加载XML配置文件GenericApplicationContext context = new GenericApplicationContext(); new XmlBeanDefinitionReader(context).loadBeanDefinitions("services.xml", "daos.xml"); context.refresh();ApplicationContext还有其它的方法,但是理论上,我们的代码不应该去调用这些方法,甚至是getBean,因为调用这些方法,就意味着我们的代码和Spring耦合了。 -
Bean 简介
在容器中,我们编写的对bean的配置元数据表现为
BeanDefinition对象。这个对象中包含以下的元数据:- 一个限定类名:特别的,当配置的是一个接口时,将会定义它的实现类。
- Bean的行为配置元素,这将描述bean在容器总应该如何运行。
- bean依赖的其他bean的引用,这些引用也被称为合作者或者依赖。
- 设置新建对象的配置,如链接池的大小。
ApplicationContext的实现类也允许注册已经存在由用户自己实例化的尚且不在容器中的对象。调用ApplicationContext的getBeanFactroy()方法,得到一个DefaultListableBeanFactroyBean工厂的实现类对象,调用DefaultListableBeanFactroy的registerSingletion()或者registerBeanDifinition()来注册bean -
命名Bean
每个Bean都已一到多个标识符,大部分情况下只有一个,在存在多个标识符的情况下,初第一个外的标识符被认定为Bean的别名。
在基于XML的配置中,可以使用
id属性、name属性或者两个都是用来命名Bean。id标签只能定义一个名称,name标签可以定义多个名称,名称之间用,、;或者是空格来隔开。容器规定Bean的
id应该是唯一的。容器不强制规定需要定义
id或者name属性,如果不需要引用这个bean,我们就可以不提供id和name,否则必须命名Bean。在Bean的定义之外为其指定别名:
<!-- 为名为bean的Bean取别名为beanA --> <alias name="bean" alias="beanA"/> <!-- 为名为bean的Bean取别名为beanB --> <alias name="bean" alias="abeanB"/> -
实例化Bean
我们在
<bean/>标签中通过class属性指定bean的类型,我们又两种使用class属性的方式:- 通常情况下,容器直接通过反射调用构造器构造对象。
- 如果类存在构造对象的静态工厂方法,在这种情况下,容器可以通过调用工厂方法来构造对象。
内部类的名称:如果我们想要定义一个嵌套类bean,我们必须使用嵌套类的二进制名称。例如:在
com.example包中有一个SomeThing类,这个类嵌套了一个嵌套类OtherThing。
那么在定义这个嵌套类时,class属性的值应该是:com.example.SomeThing$OtherThing。这里使用$将嵌套类名与外围基类名隔开。通过构造器实例化Bean
大部分普通的类都可以通过这种方式实例化Bean,类不需要实现任何指定的接口或者需要按照指定的方式编写,简单的一些约定就足够了。比如需要一个默认的(空的)构造器。
事实上,SpringIoC容器可以管理任何的类,不管是否符合JavaBean规格。
通过构造器实例化Bean的配置方式:
<bean id="exampleBean" class="examples.ExampleBean"/> <bean id="ontherExampleBean" class="examples.OntherExampleBean"/>通过工厂方法实例化Bean
当一个类存在静态工厂方法时,使用
class属性指定bean的类型,使用factory-method属性指定这个类的工厂方法的名字。工厂方法应该能够被调用且返回一个存活的对象。下面的定义通过调用静态工厂方法来实例化Bean,定义没有指定返回对象的类型,只指定了工厂方法所存在的类。工厂方法
createInstance()必须是静态方法<bean id="clientService" class="examples.ClientService" factory-method="createInstance"/>下面的
ClientService类符合上面的定义public class ClientService{ public static ClientService clientService = new ClientService(); public ClientService(){} public static ClientService createInstance(){ return clientService; } }通过实例工厂方法实例化Bean
同使用静态工厂方法相似,该方法通过调用已近存在于容器中的对象的非静态方法来实例化Bean。
<!-- 工厂bean, 有一个名为createClientServiceInstance的方法--> <bean id="serviceLocator" class="examples.DefaultServiceLocator"> <!-- inject any dependencies required by this locator bean --> </bean> <!-- 通过实例工厂实例化的bean --> <bean id="clientService" factory-bean="serviceLocator" factory-method="createClientServiceInstance"/>
本文深入探讨Spring框架中的IoC(Inversion of Control)容器原理,解释依赖注入(DI)概念,展示如何使用XML配置元数据来定义、实例化和配置Bean。同时,文章还介绍了ApplicationContext接口及其实现类在企业级应用中的作用。

598

被折叠的 条评论
为什么被折叠?



