Spring Core 官方文档阅读笔记(一)
依赖
- idref元素
<!-- 使用idref元素 -->
<bean id="theTargetBean" class="..."/>
<bean id="theClientBean" class="...">
<property name="targetName">
<idref bean="theTargetBean"/>
</property>
</bean>
<!-- 使用value元素 -->
<bean id="theTargetBean" class="..." />
<bean id="client" class="...">
<property name="targetName" value="theTargetBean"/>
</bean>
如上述代码所示,idref的作用基本与value一致,不同点是,idref元素允许容器在部署时验证引用的bean命名是否真实存在,因此在实际项目使用时,可以优先考虑使用idref
- 在property直接注入匿名Bean
<bean id="outer" class="...">
<!-- instead of using a reference to a target bean, simply define the target bean inline -->
<property name="target">
<bean class="com.example.Person"> <!-- this is the inner bean -->
<property name="name" value="Fiona Apple"/>
<property name="age" value="25"/>
</bean>
</property>
</bean>
内部Bean不需要定义ID或名称
- 集合注入
<bean id="moreComplexObject" class="example.ComplexObject">
<!-- results in a setAdminEmails(java.util.Properties) call -->
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.org</prop>
<prop key="support">support@example.org</prop>
<prop key="development">development@example.org</prop>
</props>
</property>
<!-- results in a setSomeList(java.util.List) call -->
<property name="someList">
<list>
<value>a list element followed by a reference</value>
<ref bean="myDataSource" />
</list>
</property>
<!-- results in a setSomeMap(java.util.Map) call -->
<property name="someMap">
<map>
<entry key="an entry" value="just some string"/>
<entry key ="a ref" value-ref="myDataSource"/>
</map>
</property>
<!-- results in a setSomeSet(java.util.Set) call -->
<property name="someSet">
<set>
<value>just some string</value>
<ref bean="myDataSource" />
</set>
</property>
</bean>
- 集合合并
当存在有继承关系的集合时,可以使用merge元素合并父子集合,即子集合包含父集合。如下代码所示,child的adminEmails元素就包含了parent的adminEmails集合
<beans>
<bean id="parent" abstract="true" class="example.ComplexObject">
<property name="adminEmails">
<props>
<prop key="administrator">administrator@example.com</prop>
<prop key="support">support@example.com</prop>
</props>
</property>
</bean>
<bean id="child" parent="parent">
<property name="adminEmails">
<!-- the merge is specified on the child collection definition -->
<props merge="true"> <!-- 若不需要合并,则改为false -->
<prop key="sales">sales@example.com</prop>
<prop key="support">support@example.co.uk</prop>
</props>
</property>
</bean>
<beans>
合并操作仅限于相同的集合类型,尝试合并不同的集合类型会引发异常。
merge必须指定在子定义上,如上述配置中的child,若指定在parent,则不生效。
- 泛型集合的注入
public class SomeClass {
private Map<String, Float> accounts;
public void setAccounts(Map<String, Float> accounts) {
this.accounts = accounts;
}
}
<beans>
<bean id="something" class="x.y.SomeClass">
<property name="accounts">
<map>
<entry key="one" value="9.99"/>
<entry key="two" value="2.75"/>
<entry key="six" value="3.99"/>
</map>
</property>
</bean>
</beans>
- 空字符串和空指针注入
<bean class="ExampleBean">
<property name="email" value=""/>
</bean>
<bean class="ExampleBean">
<property name="email">
<null/>
</property>
</bean>
- c命名空间
c命名空间用来配置构造函数的参数,如下所示
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="beanTwo" class="x.y.ThingTwo"/>
<bean id="beanThree" class="x.y.ThingThree"/>
<!-- traditional declaration with optional argument names -->
<bean id="beanOne" class="x.y.ThingOne">
<constructor-arg name="thingTwo" ref="beanTwo"/>
<constructor-arg name="thingThree" ref="beanThree"/>
<constructor-arg name="email" value="something@somewhere.com"/>
</bean>
<!-- c-namespace declaration with argument names -->
<bean id="beanOne" class="x.y.ThingOne"
c:thingTwo-ref="beanTwo"
c:thingThree-ref="beanThree"
c:email="something@somewhere.com"/>
</beans>
c命名空间可以通过索引来指定参数
<bean id="beanOne" class="x.y.ThingOne"
c:_0-ref="beanTwo"
c:_1-ref="beanThree"
c:_2="something@somewhere.com"/>
- 复合属性名
<bean id="something" class="things.ThingOne">
<property name="fred.bob.sammy" value="123" />
</bean>
需要保证sammy前的fred和bob属性都不是null,否则将抛出NullPointerException
- depends-on
当一个Bean依赖于另一个Bean,可以使用depends-on来指定初始化顺序,如下:
<bean id="beanOne" class="ExampleBean" depends-on="manager"/>
<bean id="manager" class="ManagerBean" />
若依赖多个bean,则可以使用逗号、分号或空格来分隔
<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
<property name="manager" ref="manager" />
</bean>
<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
- 懒惰初始化
默认情况下,ApplicationContext会在容器创建时初始化所有托管的bean,我们可以通过lazy-init元素来开启懒惰初始化,使bean在被使用时才执行初始化,如下所示
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean"/>
但是,懒惰初始化可能会因为depends-on而失效,如下
<bean id="lazy" class="com.something.ExpensiveToCreateBean" lazy-init="true"/>
<bean name="not.lazy" class="com.something.AnotherBean" depends-on="lazy"/>
此时,lazy-init失效
可以在beans标签中指定default-lazy-init元素来控制容器级别的延迟初始化
<beans default-lazy-init="true">
<!-- do something -->
</beans>
- 自动装配--@Autowire
自动装配有四种模式,分别为
- no:默认,无自动装配,Bean引用必须由ref元素指定
- byName:根据属性名称装配bean,spring查找与需要自动装配的属性名相同的bean
- byType:如果容器中只存在一个属性类型的bean,则允许属性自动装配。如果存在多个,则会抛出异常
- constructor:适用于构造函数,如果容器中没有构造函数参数类型的一个bean,则会抛出异常。
可以通过
<beans default-autowire="no/byName/byType/constructor">
来指定容器的自动装配模式。当模式为byType,并且同时存在两个相同类型的bean时,可以通过
<bean autowire-candidate="false">
来排除不需要的bean,如下:
<beans default-autowire="byType">
<bean id="monkeyA" class="example.Monkey" />
<!-- 排除MonkeyB,即后面在使用Monkey类型的自动装配时,只会装配MonkeyA -->
<bean id="monkeyB" class="example.Monkey" autowire-candidate="false" />
</beans>
也可以通过设置装配的优先级来指定优先使用哪个bean,避免报错,如下:
<beans default-autowire="byType">
<bean id="monkeyA" class="example.Monkey" />
<!-- 优先使用MonkeyB -->
<bean id="monkeyB" class="example.Monkey" primary="true" />
</beans>
- ApplicationContextAware
可以通过实现ApplicationContextAware接口来获取spring容器的功能,如下代码:
public class CommandManager implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Object process(Map commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
protected Command createCommand(){
return this.applicationContext.getBean("command", Command.class);
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeanException {
this.applicationContext = applicationContext;
}
}
- lookup方法注入
如果遇到一个单例bean依赖于一个多例bean时,可以采用上一条中的ApplicationContextAware的方法来解决,也可以通过lookup方法注入来解决,如下代码所示:
public abstract class CommandManager {
public Object process(Map commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
protected abstract Command createCommand();
}
<bean id="myCommand" class="example.Command" scope="prototype">
</bean>
<bean id="commandManager" class="example.CommandManager">
<lookup-method name="createCommand" bean="myCommand"/>
</bean>
或者可以使用@lookup注解,如下:
public abstract class CommandManager {
public Object process(Map commandState) {
Command command = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup("myCommand")
protected abstract Command createCommand();
}
若抽象函数的返回值的类型唯一,则可以写成如下方式:
public abstract class CommandManager {
public Object process(Map commandState) {
MyCommand myCommand = createCommand();
command.setState(commandState);
return command.execute();
}
@Lookup
protected abstract MyCommand createCommand();
}
- ServiceLocatorFactoryBean注入
除了12和13两种解决办法外,还可以使用ServiceLocatorFactoryBean来解决scope不同的依赖问题,如下代码:
public interface ServiceFactory {
public MyService getService(String name);
}
<beans>
<bean id="myService" class="example.MyService" singleton="false" />
<bean id="myServiceFactory" class="org.springframework.beans.factory.config.ServiceLocatorFactoryBean">
<property name="serviceLocatorInterface" value="example.ServiceFactory" />
</bean>
<bean id="clientBean" class="example.MyClientBean">
<property name="myServiceFactory" ref="myServiceFactory" />
</bean>
</beans>
public class MyClientBean {
private ServiceFactory myServiceFactory;
public void setMyServiceFactory(ServiceFactory myServiceFactory) {
this.myServiceFactory = myServiceFactory;
}
public void doSomething(String name) {
MyService service = this.myServiceFactory.getService(name);
// ...
}
}
-
方法替换
实现org.springframework.beans.factory.support.MethodReplacer 接口可以使用replaced-method元素将已存在的方法实现替换为已部署的bean -
Bean定义的继承
子类可以继承父类的配置
<bean id="inheritedTestBean" abstract="true"
class="org.springframework.beans.TestBean">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="inheritsWithDifferentClass"
class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBean" init-method="initialize">
<property name="name" value="override"/>
<!-- the age property value of 1 will be inherited from parent -->
</bean>
ApplicationContext默认预先实例化所有的单例Bean,如果某个Bean有一个父类Bean定义,并且父类只作为模版,必须确保Bean的定义里设置abstract="true"
<bean id="inheritedTestBeanWithoutClass" abstract="true">
<property name="name" value="parent"/>
<property name="age" value="1"/>
</bean>
<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
parent="inheritedTestBeanWithoutClass" init-method="initialize">
<property name="name" value="override"/>
<!-- age will inherit the value of 1 from the parent bean definition-->
</bean>