前言
在我的前一篇博客Spring Action笔记(一)初识Spring中,我介绍了Spring的整体思想和框架能力,这一篇没有前一篇深奥,不需要努力地思考Spring中的思想,只需要按照Spring的规则,学会如何使用Spring配置Bean。当然,前提是你理解了什么是Bean,什么是装配Bean,什么是Bean容器,为什么要把Bean放到容器里装配,如果不懂,请再读一遍前面一篇博客或者其他介绍Spring思想的资料。
这一章节里虽然没有太多需要我们思考和领悟的思想,只需要学习如何遵循Spring的规则来运用好Spring的特性,但我仍然不想把这篇博客当成是你的工具书,在不懂语法的时候才来翻看一下。事实上已经有很多写得更好更详细的博客已经做了这样的事,我无需再重复一次。我此篇博客的目的是从装配Bean的范畴来弄清楚,Spring支持多少种玄妙的装配功能,为何有这么多种,每种都是在什么情况下使用,以便之后我们在使用的时候可以灵活地运用。
声明Bean
声明Bean的目的就是告诉Spring,来,帮我创建一个类吧,我告诉你类的类型是什么,以及创建类需要依赖的东西如何获取。再高级点就是告诉你,我所有使用这个类的地方要独占一个实例还是和别人共享一个实例。Spring也不是高高在上,让人敬而远之的,它仍然像我们大多数人一样,用XML做配置(放心,之后会有炫酷的方式)。简单的Spring声明长下面这样。
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="student" class="test.Student"> <property name="name" value="张三"/> <property name="teacher" ref="teacher"/> </bean> <bean id="teacher" class="test.Teacher"> <property name="name" value="李四"/> </bean> </beans>
id将是Bean的唯一标识,以后别人要用的时候(别人的属性里有你或构造函数里有你)就指定它了,看到teacher了吗,对,就是使用ref来引用的。
当然,世界是复杂的,需求的多样的,这么简单的场景是这辈子都很难碰到的。这下有人跳出来了大喊,我的类构造函数有参数,如何创建,我的类不是通过构造函数创建的,是通过工厂方法创建的,怎么办?莫急,让我再甩你一个示例,相信聪明的你不用解释也能看懂。
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="car1" class="com.wul.spring.bean.factory.StaticCarFactory" factory-method="getCar"> <constructor-arg value="audi"></constructor-arg> </bean> </beans>
等等,我还有需求(或者疑惑),容器帮我们创建Bean,我们在很多地方使用(注入到很多地方),是多个实例还是单个实例?如果有这种思考,我相信你很可能不只是菜鸟,小白,只在这里寻求语法的初初级程序员了,那么让你进一步思考下,如果你是框架,你会怎么做?其实框架既人性化又懒,懒(灵活)的是它把这个问题留给使用者,自己不做控制,所以,猜对了,你可以自己告诉框架你要单例还是多个实例,使用scope参数配置。人性化的是它帮你预先定义了单例模式(为啥是单例?我也不明白,明明我平时只有在必须的时候才用单例的,不应该的默认行为)
等等,我还有需求。。啪!哪来这么多需求(产品狗已哭晕在地上)。施主莫急,你的需求(合理的)Spring都会一一为你解决,我将在后面将Spring的这些能耐一一列出。
Spring创建Bean配置列表
- id:Bean的唯一标识
- class:Bean的类型
- factory-method:创建Bean的工厂方法
- scope:Bean的实例类型
- init-method:实例化后初始化的函数
- destory-method:销毁前调用的函数
- constructor-arg:构造器参数
注入Bean属性
Bean创建之后,有时并不能立即就使用,需要设置好Bean的各种属性,Spring也提供渠道来完成这事。
简单属性、其他Bean类型的属性、内部(独占的)Bean,List、Map、Set、Array、null这些属性通通都支持。,下面是一个简单示例
<bean id="kenny" class="com.springinaction.springidol.Instrumentalist"> <property name="song" value="Jingle Bells" /> <property name="instrument1" ref="saxophone" /> <property name="instrument2"> <bean class="com.springinaction.springidol.Saxophone" /> </property> <property name="instruments3"> <list> <ref bean="guitar" /> <ref bean="cymbal" /> <ref bean="harmonica" /> </list> </property> <property name="instruments4"> <map> <entry key="GUITAR" value-ref="guitar" /> <entry key="CYMBAL" value-ref="cymbal" /> <entry key="HARMONICA" value-ref="harmonica" /> </map> </property> <property name="someNonNullProperty"><null/></property> </bean>
使用表达式装配
如果前面的东西都i无法满足你的需求或者让你对Spring感觉不过如此,那么现在,高级的东西来了。
对Bean的装配,不仅仅是前面那些编译期就能决定的静态内容,还可以是在运行时才知道的动态内容,表达式、运算符、别的Bean的方法、属性,统统可以用来装配Bean。如果你之前从没想过这些高级功能,现在是时候斟酌一番了,这么先进的装备,不用白不用。我们还是来看看示例,Spring使用SpEL来写表达式
<util:list id="cities"> <bean class="com.habuma.spel.cities.city" p:name="Chicago" p:state="IL" p:population="2853114"/> <bean class="com.habuma.spel.cities.city" p:name="Atlanta" p:state="IL" p:population="2853115"/> </util:list> <bean id="address" class="com.atguigu.spring.beans.Address"> <property name="city" value="#{'BeiJing'}"></property> <property name="street" value="jianglingjialu"></property> </bean> <bean id="kenny" class="com.springinaction.springidol.Instrumentalist"> <property name="tyrePerimeter" value="#{T(java.lang.Math).PI * 30}"></property> <property name="city" value="#{address.city}"></property> <property name="city" value="#{cities.[2]}"></property> <property name="city" value="#{cities.^[population gt 1000]}"></property> </bean>
总结
这篇博客真的内容不多,总结如下:
- 如何配置创建Bean,通过构造器创建或者工厂方法创建
- 如何设置Bean的属性
- 如何使用SpEL语言配置动态属性