Spring5参考指南:依赖注入(二)

简介: Spring5参考指南:依赖注入(二)

Null和Empty字符串值


Null和空字符串是不一样的,如下:


<bean class="ExampleBean">
    <property name="email" value=""/>
</bean>


上面的例子相当于:


exampleBean.setEmail("");


下面是怎么设置null:


<bean class="ExampleBean">
    <property name="email">
        <null/>
    </property>
</bean>


上面的例子相当于:


exampleBean.setEmail(null);


c-namespace


上面讲到了p-namespace专门是设置bean的属性用的,同样的c-namespace是用来设置构造函数参数的,如下所示:


<bean id="exampleBeanA" class="com.flydean.beans.ExampleBean">
        <constructor-arg type="int" value="7500000"/>
        <constructor-arg type="java.lang.String" value="42"/>
    </bean>
    <bean id="exampleBeanB" class="com.flydean.beans.ExampleBean"
    c:years ="10" c:ultimateAnswer="answer"
    />


depends-on


通常一个bean依赖另一个bean,我们会在XML中使用< ref/>来引用,但是这种依赖关系并不直接。我们可以使用depends-on属性来显式强制一个或多个bean在使用此元素的bean初始化之前进行初始化,如下所示:


<bean id="beanA" class="com.flydean.beans.SomeClass" depends-on="beanB"></bean>
    <bean id="beanB" class="com.flydean.beans.MovieFinder"></bean>


lazy-init


正常来说ApplicationContext中配置成单例模式的bean都会随Spring启动而初始化,如果有特殊的需要,想延长初始化该bean,则可以使用 lazy-init 。一个lazy-initialized bean告诉IOC容器在第一次请求bean实例时创建它,而不是在启动时。


<bean id="beanD" class="com.flydean.beans.MovieFinder" lazy-init="true"></bean>


但是,当一个惰性初始化bean是一个非惰性初始化的singleton bean的依赖项时

ApplicationContext会在启动时创建惰性初始化bean,因为它必须满足singleton的依赖项。


您还可以通过在< beans/>元素上使用默认的lazy init属性在容器级别控制lazy初始化,下面的示例显示:


<beans default-lazy-init="true">
    <!-- no beans will be pre-instantiated... -->
</beans>


自动装载


如果你想让Spring自动帮你注入bean的依赖bean时候,可以使用Spring的autowiring功能。autowiring 有4种模式:


模式 说明
no (默认)无自动装载。bean必须引用由ref定义的元素。对于较大的部署,不建议更改默认设置,因为显式指定合作者可以提供更大的控制度和清晰性。在某种程度上,它记录了系统的结构。
byName 按属性名称自动装载。Spring寻找与需要自动装载的属性同名的bean。例如,如果bean定义被设置为按名称自动装载,并且它包含一个master属性(即,它有一个setMaster(…)方法),那么spring将查找名为master的bean定义并使用它来设置该属性。
byType 如果容器中只有一个属性类型的bean,则允许自动装载属性。如果存在多个,则会引发一个致命的异常,这表示您不能为该bean使用byType自动装载。如果没有匹配的bean,则不会发生任何事情(未设置属性)。
constructor 类似于byType,但适用于构造函数参数。如果容器中不只有一个构造函数参数类型的bean,则会引发致命错误。


自动注入的限制和缺陷


虽然自动注入用起来很爽,但是它也有如下的缺陷:


  • property和constructor-arg的显示设置会覆盖自动注入,并且自动注入不能注入简单类型。


  • 自动注入不如显示配置精确。


  • 自动注入可能和容器中的很多bean相匹配。可能会出现问题。


从自动装载中排除Bean


使用autowire-candidate属性设置为false,可以防止bean被自动注入。该属性只会影响按类型注入的方式。如果按name注入,则不受影响。


下面是自动注入的例子:


<bean id="simpleMovieLister" class="com.flydean.beans.SimpleMovieLister" autowire="byType">
    </bean>
    <!--Setter DI -->
    <bean id="movieFinder" class="com.flydean.beans.MovieFinder">
        <property name="name" value="movie"/>
        <property name="number" value="123456"/>
    </bean>


SimpleMovieLister如下:


package com.flydean.beans;
import lombok.Data;
@Data
public class SimpleMovieLister {
    // the SimpleMovieLister has a dependency on the MovieFinder
    private MovieFinder movieFinder;
    // a setter method so that the Spring container can inject a MovieFinder
    public void setMovieFinder(MovieFinder movieFinder) {
        this.movieFinder = movieFinder;
    }
    // business logic that actually uses the injected MovieFinder is omitted...
}


在上面的例子中,movieFinder属性将会被自动注入。


方法注入


在bean的生命周期不同的时候,如果一个bean要依赖于另外一个bean则可能出现问题。 比如一个单例模式的beanA 依赖于多例模式的beanB。 因为beanA是单例模式的,所以在创建beanA的时候就已经将其依赖的beanB创建了,不可能在每次beanA需要beanB的时候都创建一个新的beanB的实例。


解决方法有很多种,我们一一进行讲解。


方法1:实现ApplicationContextAware


如果实现了ApplicationContextAware,则可以通过getBean方法在每次需要beanB的时候,请求他的新的实例,如下:


public class CommandManager implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    public Object process(Map commandState) {
        // grab a new instance of the appropriate Command
        Command command = createCommand();
        // set the state on the (hopefully brand new) Command instance
        command.setState(commandState);
        return command.execute();
    }
    protected Command createCommand() {
        // notice the Spring API dependency!
        return this.applicationContext.getBean("command", Command.class);
    }
    public void setApplicationContext(
            ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}


这种方法并不可取的,因为业务代码和Spring框架产生了耦合。方法注入是Spring IoC 容器的一个高级特性,它可以很好的处理这种情况。


查找方法注入


查找方法注入是指容器重写container-managed bean上的方法,并返回容器中另一个命名bean。查找通常涉及一个原型bean,如前一节中描述的场景中所示。Spring框架通过使用cglib库中的字节码动态生成覆盖该方法的子类来实现该方法注入。


因为使用了cglib,所以bean不能是final类,方法也不能是final类型。


查找方法不适用于工厂方法,尤其不适用于配置类中的@Bean方法,因为在这种情况下,容器不负责创建实例,因此无法动态创建运行时生成的子类。


下面是一个查找方法的例子:


public abstract class CommandManagerB {
    public Object process(Map commandState) {
        // grab a new instance of the appropriate Command interface
        AsyncCommand command = createCommand();
        return null;
    }
    // okay... but where is the implementation of this method?
    public abstract AsyncCommand createCommand();
}


这里我们定义了一个抽象类,要查找的方法就是createCommand。返回的对象类,如下:


public class AsyncCommand {
}


下面是XML配置文件:


<!-- a stateful bean deployed as a prototype (non-singleton) -->
    <bean id="myCommand" class="com.flydean.beans.AsyncCommand" scope="prototype">
        <!-- inject dependencies here as required -->
    </bean>
    <!-- commandProcessor uses statefulCommandHelper -->
    <bean id="commandManager" class="com.flydean.beans.CommandManagerB">
        <lookup-method name="createCommand" bean="myCommand"/>
    </bean>


CommandMangerB每次调用createCommand,都会返回一个新的AsyncCommand实例。


在基于注解的情况下,也可以这样使用:


public abstract class CommandManagerC {
    public Object process(Object commandState) {
        Command command = createCommand();
        return command.execute();
    }
    @Lookup("myCommand")
    protected abstract Command createCommand();
}


其中@Lookup(“myCommand”) 中的名字也可以省略,则按照默认的类型来解析。

任意方法替换


我们甚至可以使用replaced-method替换bean的方法实现。我们有个MyValueCalculator类,有一个我们想重写的方法computeValue。


public class MyValueCalculator {
    public String computeValue(String input) {
        // some real code...
        return "abc";
    }
    // some other methods...
}


一个实现了org.springframework.beans.factory.support.MethodReplacer接口的类提供了新的方法,如下所示:


public class ReplacementComputeValue implements MethodReplacer {
    public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
        // get the input value, work with it, and return a computed result
        String input = (String) args[0];
        return "def";
    }
}


bean的定义如下:


<bean id="myValueCalculator" class="com.flydean.beans.MyValueCalculator">
        <!-- arbitrary method replacement -->
        <replaced-method name="computeValue" replacer="replacementComputeValue">
            <arg-type>String</arg-type>
        </replaced-method>
    </bean>
    <bean id="replacementComputeValue" class="com.flydean.beans.ReplacementComputeValue"/>
相关文章
|
4月前
|
XML Java 测试技术
Spring Boot中的依赖注入和控制反转
Spring Boot中的依赖注入和控制反转
|
3月前
|
Java Spring 容器
彻底改变你的编程人生!揭秘 Spring 框架依赖注入的神奇魔力,让你的代码瞬间焕然一新!
【8月更文挑战第31天】本文介绍 Spring 框架中的依赖注入(DI),一种降低代码耦合度的设计模式。通过 Spring 的 DI 容器,开发者可专注业务逻辑而非依赖管理。文中详细解释了 DI 的基本概念及其实现方式,如构造器注入、字段注入与 setter 方法注入,并提供示例说明如何在实际项目中应用这些技术。通过 Spring 的 @Configuration 和 @Bean 注解,可轻松定义与管理应用中的组件及其依赖关系,实现更简洁、易维护的代码结构。
52 0
|
3月前
|
设计模式 自然语言处理 Java
简单了解下Spring中的各种Aware接口实现依赖注入
在Spring框架中,Aware接口是一组用于提供特定资源或环境信息的回调接口。这些接口被设计用来允许Bean获取对Spring容器或其他相关资源的引用,并在需要时进行适当的处理。
36 2
|
3月前
|
自然语言处理 Java 开发者
简单了解下Spring中的各种Aware接口实现依赖注入
【8月更文挑战第21天】在Spring框架中,Aware接口系列是一种特殊的机制,它允许Bean在初始化过程中获取到Spring容器或容器中的特定资源,从而实现了更加灵活和强大的依赖注入方式。本文将围绕Spring中的各种Aware接口,详细探讨它们如何帮助开发者在工作和学习中更好地实现依赖注入。
107 0
|
4月前
|
缓存 Java Spring
Spring循环依赖问题之Spring不支持构造器内的强依赖注入如何解决
Spring循环依赖问题之Spring不支持构造器内的强依赖注入如何解决
|
5月前
|
设计模式 Java 测试技术
Spring Boot中的依赖注入详解
Spring Boot中的依赖注入详解
|
5月前
|
Java Spring 容器
spring如何进行依赖注入,通过set方法把Dao注入到serves
spring如何进行依赖注入,通过set方法把Dao注入到serves
|
4月前
|
XML Java 数据格式
深入理解Spring中的依赖注入原理
深入理解Spring中的依赖注入原理
|
4月前
|
Java Spring 容器
深入理解Spring Boot中的容器与依赖注入
深入理解Spring Boot中的容器与依赖注入
|
5月前
|
XML Java 数据格式
使用 Spring 实现控制反转和依赖注入
自动装配允许Spring容器通过检查已定义的bean来自动解决协作bean之间的依赖关系。 使用XML配置有四种自动装配bean的模式: • no:默认值 - 这意味着不使用自动装配,我们必须显式地命名依赖项。 • byName:按属性名称进行自动装配,因此Spring将查找与需要设置的属性同名的bean。 • byType:类似于按名称进行自动装配,仅基于属性的类型。这意味着Spring将查找具有相同类型的属性来设置的bean。如果有多个bean具有该类型,则框架会抛出异常。 • constructor:基于构造函数参数进行自动装配,意味着Spring将查找具有与构造函数参数相同类型的bea