Spring装配Bean
经过上一章节的描述,让我们了解了Spring这个框架。接下来在本章中我我来说说Spring是怎么装配这些Bean的,以及装配Bean的几种方法。这里涉及到2个专业的术语我先介绍一下。
- IOC:Inversion of Controller 控制反转,在程序中所谓的IOC其实简单的说,就是原来有我们自己实例化的对象交给Spring容器来初始化。这时对象的实例化的权利就会反转。
- DI:dependence injection 依赖注入。在Spring创建Bean的时候,动态的讲依赖对象注入到Bean组件中。
以上就是Spring容器的2个核心要素,简单的来说就是Spring容器负责创建应用程序中的bean并通过DI来协调这些对象之间的关系,配置它们并管理它们的整个生命周期,从生存到死亡。如下图所示
Spring容器并不是只有一个。Spring自带了多个容器实现,可以归为两种不同的类型。bean工厂(由org.springframework. beans. factory.eanFactory接口定义)是最简单的容器,提供基本的DI支持,一般不使用。应用上下文(由org.springframework.context.ApplicationContext接口定义)基于BeanFactory构建,并提供应用框架级别的服务,例如从属性文件解析文本信息以及发布应用事件给感兴趣的事件监听者,企业中经常使用的,下面详细介绍一下应用上下文。
应用上下文
先了解一下ApplicationContext于BeanFactory的关系,如下图。
可以看出ApplicationContext是扩展BeanFactory的接口。BeanFactory它采取延迟加载的方案,只有在真正getBean的时候才会实例化Bean,在开发中我们一般使用ApplicationContext,它会在配置文件加载时,就会初始化Bean,并且ApplicationContext它提供不同应用层的Context实现,下面罗列的几个是你最有可能遇到的。
- AnnotationConfigApplicationContext:从一个或多个基于Java的配置类中加载Spring应用上下文。
- AnnotationConfigWebApplicationContext:从一个或多个基于Java的配置类中加载Spring Web应用上下文。
- ClassPathXmlApplicationContext:从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件作为类资源。
- FileSystemXmlapplicationcontext:从文件系统下的一个或多个XML配置文件中加载上下文义。
- XmlWebApplicationContext:从Web应用下的一个或多个XML配置文件中加载上下文定义。
无论是从文件系统中装载应用上下文还是从类路径下装载应用上下文,将bean加载到bean工厂的过程都是相似的。例如,如下代码展示了如何加载一个FileSystemXmlApplicationContext:AppliationContext context = new FileSystemXmlAppliationContext("c:/applicationContext.xml")
类似地,你可以使用ClassPathXmlApplicationContext从应用的类路径下加载应用上下文:AppliationContext context = new ClassPathXmlAppliationContext("c:/applicationContext.xml")
它们两个的使用区别在于一个在指定的文件系统路径下查找配置文件,另一个是在所有的类路径(包含JAR文件)下查找配置文件。其他应用上下文在后面使用的时候说下如AnnotationConfigApplicationContext,应用上下文准备就绪之后,我们就可以调用上下文的getBean()方法从Spring容器中获取bean。现在你应该基本了解了如何创建Spring容器,让我们对容器中bean的生命周期做更进一步的探究。
bean的生命周期
在传统的Java应用中,bean的生命周期很简单。使用Java关键字new进行bean实例化,然后该bean就可以使用了。一旦该bean不再被使用,则由Java自动进行垃圾回收。
相比之下,Spring容器中的bean的生命周期就显得相对复杂多了。正确理解Spring bean的生命
周期非常重要,因为你或许要利用Spring提供的扩展点来自定义bean的创建过程。下图展示
了bean装载到Spring应用上下文中的一个典型的生命周期过程。
- Spring对bean进行实例化;
- Spring将值和bean的引用注入到bean对应的属性中;
- 如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBean-Name()方法;
- 如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入。或者如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;
- 如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessBeforeInitialization()方法;
- 如果bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet()方法。
- 如果bean使用init-method声明了初始化方法,该方法也会被调用;
- 如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessAfterInitialization()方法;
- 此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
- 如果bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。
- 如果bean使用destroy-method声明了销毁方法,该方法也会被调用。
对于bean生命周期的方法,第三步第四步是让Bean了解spring容器,第五步和第八步可以针对指定的bean进行功能增强,这是一般会使用动态代理。第六步和第十步通过实现指定的接口完成init和destory操作但是开发中一般不用第六步和第十步而是使用第七步于第十一步的初始化于销毁操作因为他是无耦合的,但是必须在配置文件中指定初始化于销毁的方法,注意destory-method只针对scope=singleTon有效果。
现在你已经了解了如何创建和加载一个Spring容器。但是一个空的容器并没有太大的价值,在你把东西放进去之前,它里面什么都没有。为了从Spring的DI中受益,我们必须将应用对象装配进Spring容器中。下面简单的介绍spring配置的可选方案。
装配bean
作为开发人员,你需要告诉Spring要创建哪些bean并且如何将其装配在一起。当描述bean如何进行装配时,Spring具有非常大的灵活性,下面介绍一下配置Spring容器的最常见的三种方法。
- 在XML中进行显式配置
- 隐式的bean发现机制和自动装配
- 在java中进行显式配置
乍看上去,提供三种可选的配置方案会使Spring变得复杂。每种配置技术所提供的功能会有一些重叠,所以在特定的场景中,确定哪种技术最为合适就会变得有些困难。但是,不必紧张——在很多场景下,选择哪种方案很大程度上就是个人喜好的问题,你尽可以选择自己最喜欢的方式。在一般的公司中很多都是用的XML显式配置和自动装配相结合的方式,至于java中显式的配置我目前了解是一般在Spring Boot中用到。(ps:Spring Boot后面再说,现在了解它是崭新的项目,以spring的视角,致力于简化Spring本身)
通过XML装配bean
再使用XML为spring装配bean之前,需要创建一个XML文件,并且要以<beans>
元素为根。最简单的SpringXML配置为如下所示:
可以看出再使用XML的时候,需要在配置文件的顶部声明多个XML模式(XSD)文件,这些文件定义了Spring的元素。用来装配bean的最基本的XML元素包含在spring-beans模式之中,在上面这个XML文件中,它被定义为根命名空间。<bean>
。<bean id="userService" class="com.huay.demo.UserServiceImpl" />
Spring框架中<bean>
标签的配置
- id属性: Bean起个名字,在约束中采用ID的约束,唯一
取值要求:必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号。id:不能出现特殊字符。 - name属性: Bean起个名字,没有采用ID的约束(了解)
取值要求:name:可以出现特殊字符.如果没有id的话 , name可以当做id使用。 - class属性: Bean对象的全路径
- scope属性: scope属性代表Bean的作用范围
- 单例(Singleton):在整个应用中,只创建bean的一个实例。它是默认值。
- 原型(Prototype):每次注入或者通过Spring应用上下文获取的时候,都会创建一个新的bean实例。
- 会话(Session):在Web应用中,为每个会话创建一个bean实例。
- 请求(Rquest):在Web应用中,为每个请求创建一个bean实例。
- init-method属性:当bean被载入到容器的时候调用init-method属性指定的方法
- destroy-method属性:当bean从容器中删除的时候调用destroy-method属性指定的方法,但是bean对象必须为单例的,web容器中会自动调用,但是main函数或测试用例需要手动调用(需要使用ClassPathXmlApplicationContext的close()方法)。
接下来我们完善XML配置文件如下图所示:
在写一个Person类和测试demo。
运行后得到的结果为:
这样一个Spring的小栗子就完成了,但读者可以在脑海中想一下这个person类是如何从创建到销毁的,还有抛出一个问题,配置文件中的<property>
是如何设置person中的成员属性name的?有没有其他的办法实现?答案见下一章节。