1. 在spring配置文件中,如果对一个property进行直接赋值,可使用<value>元素,spring负责将值转化为property指定的类型;也可以直接在property元素上使用value属性来赋值;
2. 构造函数注入,应使用<constructor-arg>元素来赋值,该元素有三个属性,你可以指定来对赋值的构造函数参数进行区分:type、index或者name,但是当你使用name属性时,你应该放置@ConstructorProperties annotation到构造函数上去显式的指定构造函数参数名;
3. spring中对于同名的bean,后一个会覆盖前一个;
4. 对于指定bean的名字,可以通过<bean>的id属性,也可以通过name属性,id属性只能指定一个名字,name属性可以指定多个,并且用逗号隔开;
5. 如果通过property注入,我们可以在schema上加上xmlns:p="http://www.springframework.org/schema/p",那么就可以在bean元素上直接加上p:propertyName="value"来进行赋值;同理,通过constructor来注入,则必须加上xmlns:c="http://www.springframework.org/schema/c"的schema,并在bean元素上加上c:argumentName="value"来赋值;
6. 我们在加载一个spring的配置文件,应该使用GenericXmlApplicationContext类,默认该类从classpath下面去加载配置文件;GenericXmlApplicationContext类的某个构造函数接受多个配置文件作为一个字符串的数组;
7. 为了引用其他的bean,你可以使用<ref bean="bean name"/>元素,ref元素中的bean属性可以引用到其他任何一个配置文件中的bean,如果只想引用相同xml文件中的bean,我们应该使用<ref local="bean name"/>,我们也可以在property元素或者constructor-arg元素上使用ref属性来引用其他的bean;对于schema,我们可以使用p:propertyName-ref="bean name"来引用其他的bean;
8. <bean/>元素的autowire属性,默认情况下只用于这个bean所有properties的autowire,它包含3个可能的值:
byName: 根据bean的属性名找到相同名的bean;
byType: 根据bean的属性类型找到相同类型的bean;
constructor: 用于bean的构造函数的autowire,它首先根据构造函数的参数类型找到相同类型的bean,然后再确定最佳的构造函数;
当使用autowire byType的时候,如果存在相同类型的多个bean,就会抛异常,那么可以在某一个bean的<bean>元素上加上primary="true",则这个bean在autowire byType时会优先使用;
对于autowire的bean属性,如果spring找不到响应的bean,那么spring就会设置一个null值;在用户使用该属性的时候,可能会得到NullPointerException异常;如此我们可以使用以下两种方法来规避:
a. 为某个property创建一个setter方法,并使用@Required annotation;
b. 为某个property加上@Autowired annotation,隐式的包涵了@Required;
对于某些bean,我们不想让其被其他bean autowire,我们可以在这个<bean>元素上加上autowire-candidate="false";
9. 我们可以在一个配置文件中,使用<import>标记去引用其他的配置文件;
10. spring提供了3个元素去定义集合:<list>、<set>、<map>;
对于集合<list>和<set>,其中的item可以是:<value>、<ref>、<bean>、<idref>、<null/>等元素;
对于<map>,其中的item必须是<entry>元素,<entry>元素中的key必须放在<key>元素下,value直接放在<entry>元素下面;无论是key或者value的值,可以是<value>、<ref>、<bean>、<idref>、<null/>元素中的任何一种;<entry>元素也包含有key、value、key-ref、value-ref等属性;
spring为java.util.Properties集合提供了<props>元素,该元素中的每一个item都必须是<prop>元素,该<prop>元素包含有key属性;
11. 对于上面提到的创建集合所使用的元素,他们不能被使用来创建一个独立的bean,如果要创建一个独立的bean,我们必须要使用util schema,我们需要加入xmlns:util="http://www.springframework.org/schema/util",并且在xsi:schemaLocation中加入http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd;然后我们就可以使用<util:list>、<util:set>、<util:map>来创建集合bean,这三种元素都提供了list-class、set-class、map-class属性来指定要创建集合的类型;
12. <bean>元素有一个scope属性,用来指定创建的bean实例的作用域;值可能是:
singleton: 在这个spring容器里面只有一个实例;
prototype: 每一次请求都会创建一个新的bean实例;
request: 每一次请求创建一个新的实例,在Web Application中有效;
session: 每一个session创建一个新的实例,在Web Application中有效;
global-session: 对每一个global HTTP session创建一个新的实例,在Web Application中有效;
13. 为了加载一个property文件进入spring容器,并让其他bean使用;spring提供了PropertySourcesPlaceholderConfigurer类,它的location属性用来指定property文件的位置;
然后我们就可以在配置文件中使用${key:default_value}方式来引用property文件中的property;
如果我们要读取一个文件的内容,spring提供了一个Resource类型,你只需在配置文件中将一个字符串赋值给这个类型的属性,spring容器会自动将其转换为Resource实例,这个字符串可以根据文件的不同位置指定不同的前缀,比如文件系统中的文件,就以file开始,classpath中的文件就以classpath开始;如果实在classpath中的一个特殊的包中,可以使用这样的形式来指定Resource:classpath:com/apress/springrecipes/shop/banner.txt;
14. 为了让Spring支持多语言化,Spring提供了通过特定的local去properties文件读取message的方式,这些message必须被放在properties文件里面,这样的文件被叫做resource bundle,这些文件应该被放置在classpath 的根目录下,并且文件名必须遵守messages_<language_code>_<country_code>.properties这样的约束,我们可以创建一个ReloadableRsourceBundleMessageSource的bean去读取message,但是由于必须让Application Context知道这是一个读取message的bean,所以这个bean的名字必须是messageSource,这个bean的basenames属性resource bundle文件的文件名(不包含language code和country code部分);
在Spring context中,如果一个bean需要使用到这些message,则需要把messageSource bean注入到那个bean里面;
15. Spring Container中bean的生命周期:
- 通过构造函数或者工厂方法创建bean实例;
- 设置bean的属性值;
- 调用bean的初始化方法;
- 使用bean;
- 当container被关闭时;调用析构器方法;
在bean的定义中,初始化方法和析构器方法都是通过<bean/>元素的init-method和detory-method来指定的;
16. 一般而言,spring context中的所有bean会在Spring Container被启动后立即执行初始化;为了避免某些过渡消耗时间和资源的bean的创建,我们可以在这样的<bean>元素上设置lazy-init="true"属性;
17. 某些时候,一些bean要依赖自另外一些bean被创建后,才能被创建(两者之间可能并没有引用的关系);我们可以使用<bean/>元素的depends-on属性,该属性可以指定一个或多个bean names,并用逗号隔开;
18. 我们可能想在Spring Container中的每一个bean的初始化方法被调用之前或者之后执行一些任务,比如做一些属性验证等;我们可以创建一个类,并使之继承自BeanPostProcessor接口;
并实现该接口中的postProcessBeforeInitialization方法和postProcessAfterInitialization方法;这样bean的生命周期就成为:
- 通过构造函数或者工厂方法创建bean实例;
- 设置bean的属性值;
- 将bean实例传递给BeanPostProcessor实现类的postProcessBeforeInitialization方法;
- 调用bean的初始化方法;
- 将bean实例传递给BeanPostProcessor实现类的postProcessAfterInitialization方法;
- 使用bean;
- 当container被关闭时;调用析构器方法;
BeanPostProcessor实现类必须被申明在spring配置文件中;
19. 除开Spring Container实现bean实例的初始化之外,Spring还提供了其他三种方式去创建Bean:
- 静态工厂方法;
- 实例工厂方法;
- Spring FactoryBean
如果你想利用静态工厂方法来创建bean实例,你需要在<bean/>节点中通过class属性指定静态类的类型,在factory-method属性中指定方法名,然后通过<constructor-arg/>子元素传入方法参数;
如果你要使用实例工厂方法,你需要在<bean/>节点上通过factory-bean指定工厂方法所在的bean name,在factory-method属性中指定方法名,然后通过<constructor-arg/>子元素传入方法参数;
如果你要利用FactoryBean来创建bean实例,你需要继承AbstractFactoryBean抽象类,并复写createInstance()方法去创建目标bean实例,为了让其他的bean能autowire这个bean,还得实现getObjectType()方法去返回目标bean的类型;
每一次Spring Container去请求FactoryBean,得到的都是目标bean的实例,要想得到FactoryBean本身,需要在bean name前加上&符号;
20. 如果想根据不同的环境给予bean不同的初始值,你可以创建多个具有相同名字的bean,然后把它们放在不同的profile中,每一个profile都通过<beans/>元素的指定,<beans/>元素的profile属性说明了profile的名字;每一个<beans/>元素可以包含多个bean,也可以为其profile指定多个名字,并用逗号分割开来;
为了在Spring Container启动时指定加载哪一个profile,你可以通过以下3种方式来做到:
- 在加载配置文件之前,调用GenericXmlApplicationContext类的getEnvironment().setActiveProfiles("","")
- 在运行之前,传入JVM参数-Dspring.profiles.active="XXX,XXX"
- 为war包的web.xml文件中的servlet传入spring.profiles.active初始化参数:
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <init-param> <param-name>spring.profiles.active</param-name> <param-value>XXX</param-value> </init-param> </servlet>
有时候,为了防止用户忘记指定profiles导致出错,我们还可以指定DefaultProfiles:
- 调用GenericXmlApplicationContext类的getEnvironment().setDefaultProfiles("","")
- 传入JVM参数-Dspring.profiles.default="XXX,XXX"
- 为war包的web.xml文件中的servlet传入spring.profiles.default初始化参数:
<servlet> <servlet-name>dispatcher</servlet-name> <servlet-class> org.springframework.web.servlet.DispatcherServlet </servlet-class> <init-param> <param-name>spring.profiles.default</param-name> <param-value>winter</param-value> </init-param> </servlet>