Spring Core 官方文档阅读笔记(一)

依赖

  1. 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

  1. 在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或名称

  1. 集合注入
<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>
  1. 集合合并
    当存在有继承关系的集合时,可以使用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,则不生效。

  1. 泛型集合的注入
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>
  1. 空字符串和空指针注入
<bean class="ExampleBean">
    <property name="email" value=""/>
</bean>

<bean class="ExampleBean">
    <property name="email">
        <null/>
    </property>
</bean>
  1. 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"/>
  1. 复合属性名
<bean id="something" class="things.ThingOne">
    <property name="fred.bob.sammy" value="123" />
</bean>

需要保证sammy前的fred和bob属性都不是null,否则将抛出NullPointerException

  1. 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" />
  1. 懒惰初始化
    默认情况下,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>
  1. 自动装配--@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>
  1. 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;
    }
}
  1. 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();
}
  1. 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);
        // ...
    }
}
  1. 方法替换
    实现org.springframework.beans.factory.support.MethodReplacer 接口可以使用replaced-method元素将已存在的方法实现替换为已部署的bean

  2. 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>
posted @ 2020-04-27 08:11  kuromaru  阅读(200)  评论(0)    收藏  举报