java有参数的构造函数如何注⼊_Spring5参考指南:依赖注⼊依赖注⼊
依赖注⼊就是在Spring创建Bean的时候,去实例化该Bean构造函数所需的参数,或者通过Setter⽅法去设置该Bean的属性。
Spring的依赖注⼊有两种基于构造函数的依赖注⼊和基于setter的依赖注⼊。
基于构造函数的依赖注⼊
构造函数的注⼊是通过构造函数的参数来实现的。如下所⽰:
public class ExampleBean {// Number of years to calculate the Ultimate Answerprivate int years;// The Answer to Life, the Universe, and Everythingprivate 该Bean有⼀个两个参数的构造函数,那么怎么注⼊这些参数呢?
有三种⽅法。
⽅法1:按构造函数的类型匹配:
这⾥通过指定参数的类型,即可以指定哪个参数是years,哪个参数是ultimateAnswer。
jdk怎么使用
⽅法2:构造函数索引:
Spring中可以通过构造函数的索引来指定特定的参数。要注意Spring的索引是从0开始的。
⽅法3:构造函数名字匹配:
如果通过构造函数的名字来匹配,需要注意必须在编译的时候开启调试标志,要不然Spring不能在构造函数中到参数名。
如果不想启⽤调试标志,则必须使⽤@ConstructorProperties JDK注解显式命名构造函数参数。
public class ExampleBeanWithConstructorProperties {// Number of years to calculate the Ultimate Answerprivate int years;// The Answer to Life, the Univer 基于Setter的注⼊
Setter注⼊主要⽤来⽆参构造器或者获得对象实例之后才设置对象的属性。下⾯是Setter的例⼦:
public class SimpleMovieLister {// the SimpleMovieLister has a dependency on the MovieFinderprivate MovieFinder movieFinder;// a setter method so that 对于的XML⽂件如下:
除了XML配置,也可以使⽤注解:@Component、@Controller。或者使⽤@Configuration注解中的@Bean⽅法。
如何选择?
既然有这样两种注⼊⽅式,我们怎么选择呢?
通常来说,对于必须的属性,我们通过构造函数来注⼊。对于可选属性,我们通过Setter注⼊。当然你也可以在Setter⽅法中使⽤
@Required注解。
当然如果第三⽅类不公开任何setter⽅法,那么构造函数注⼊可能是DI的唯⼀可⽤形式。
循环依赖
循环依赖主要出现在构造函数注⼊的情况。
类A通过构造函数注⼊需要类B的实例,类B通过构造函数注⼊需要类A的实例。如果为要相互注⼊的类A和类B配置bean,那么SpringIOC 容器在运⾏时检测到这个循环引⽤,会抛出BeanCurrentlyInCreationException。
解决⽅式就是使⽤Setter注⼊。
依赖注⼊的配置详解
基本类型,字符串或者其他
如果< property/>元素的value属性是基本类型,Spring会将其转换为类需要的类型,配置如下:
这是⼀个常见的Setter注⼊。为了简洁,也可以使⽤p-namespace,如下:
<?xml version="1.0" encoding="UTF-8"?>
Spring容器使⽤JavaBeans属性编辑器机制将< value/>元素中的⽂本转换为java.util.properties实例。这是⼀个很好的快捷⽅式,如下所⽰:
jdbc.driver.className= sql.jdbc.Driverjdbc.url=jdbc: mysql://localhost:3306/mydb
注意上⾯例⼦中的value⾥⾯的值。
ref
通过< ref/>标记的bean属性允许在同⼀容器或⽗容器中创建对任何bean的引⽤,⽽不管它是否在同⼀XML⽂件中。bean属性的值可以与⽬标bean的id属性相同,也可以与⽬标bean的name属性中的⼀个
值相同。以下⽰例显⽰如何使⽤ref元素:
内部bean
在< property/> 或者 < constructor-arg/>元素内部的< bean/>元素可以定义⼀个内部bean,下⾯是个例⼦:
内部bean定义不需要ID或名称。如果指定,容器也不会使⽤这个值作为标识符。容器在创建时也忽略作⽤域标志,因为内部bean总是匿名的,并且总是⽤外部bean创建的。不可能单独访问内部bean,也不可能将它们注⼊到除封闭bean之外的协作bean中。
集合
< list/>, < set/>, < map/>,和 < props/> 分别被⽤来设置Java Collection类型List, Set, Map,和 Properties 类型的属性和参数。 下⾯是个例⼦:
"a list element followed by a reference"just some string
强类型集合
通过在Java 5中引⼊泛型类型,可以使⽤强类型集合。也就是说,可以声明集合类型,使其只能包含(例如)字符串元素。如果使⽤Spring将强类型集合注⼊bean,则可以利⽤Spring的类型转换⽀持,以便在将强类型集合实例的元素添加到集合之前将其转换为适当的类型。下⾯的Java类和bean定义的例⼦:
public class SomeClass {private Map accounts;public void setAccounts (Map accounts) {this.accounts = accounts;}}
Null和Empty字符串值
Null和空字符串是不⼀样的,如下:
上⾯的例⼦相当于:
exampleBean.setEmail("");
下⾯是怎么设置null:
上⾯的例⼦相当于:
exampleBean.setEmail(null);
c-namespace
上⾯讲到了p-namespace专门是设置bean的属性⽤的,同样的c-namespace是⽤来设置构造函数参数的,如下所⽰:
depends-on
通常⼀个bean依赖另⼀个bean,我们会在XML中使⽤< ref/>来引⽤,但是这种依赖关系并不直接。我们可以使⽤depends-on属性来显式强制⼀个或多个bean在使⽤此元素的bean初始化之前进⾏初始化,如下所⽰:
lazy-init
正常来说ApplicationContext中配置成单例模式的bean都会随Spring启动⽽初始化,如果有特殊的需要,想延长初始化该bean,则可以使⽤ lazy-init 。⼀个lazy-initialized bean告诉IOC容器在第⼀次请求bean实例时创建它,⽽不是在启动时。
但是,当⼀个惰性初始化bean是⼀个⾮惰性初始化的singleton bean的依赖项时,ApplicationContext会在启动时创建惰性初始化bean,因为它必须满⾜singleton的依赖项。
您还可以通过在< beans/>元素上使⽤默认的lazy init属性在容器级别控制lazy初始化,下⾯的⽰例显⽰:
⾃动装载
如果你想让Spring⾃动帮你注⼊bean的依赖bean时候,可以使⽤Spring的autowiring功能。autowiring 有4种模式:
⾃动注⼊的限制和缺陷
虽然⾃动注⼊⽤起来很爽,但是它也有如下的缺陷:
property和constructor-arg的显⽰设置会覆盖⾃动注⼊,并且⾃动注⼊不能注⼊简单类型。
⾃动注⼊不如显⽰配置精确。
⾃动注⼊可能和容器中的很多bean相匹配。可能会出现问题。
从⾃动装载中排除Bean
使⽤autowire-candidate属性设置为false,可以防⽌bean被⾃动注⼊。该属性只会影响按类型注⼊的⽅式。如果按name注⼊,则不受影响。
下⾯是⾃动注⼊的例⼦:
SimpleMovieLister如下:
package com.flydean.beans;import lombok.Data;@Datapublic class SimpleMovieLister {// the SimpleMovieLister has a dependency on the MovieFinderpri 在上⾯的例⼦中,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 command
这种⽅法并不可取的,因为业务代码和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 interfaceAsyn 这⾥我们定义了⼀个抽象类,要查的⽅法就是createCommand。返回的对象类,如下:
public class AsyncCommand {}
下⾯是XML配置⽂件:
CommandMangerB每次调⽤createCommand,都会返回⼀个新的AsyncCommand实例。
在基于注解的情况下,也可以这样使⽤:
public abstract class CommandManagerC {public Object process (Object commandState) {Command command = createCommand(); 其中@Lookup(“myCommand”) 中的名字也可以省略,则按照默认的类型来解析。
任意⽅法替换
我们甚⾄可以使⽤replaced-method替换bean的⽅法实现。我们有个MyValueCalculator类,有⼀个我们想重写的⽅法computeValue。public class MyValueCalculator {public String computeValue(String input) {// some urn "abc";}// some }
⼀个实现了org.springframework.beans.factory.support.MethodReplacer接⼝的类提供了新的⽅法,如下所⽰:
public class ReplacementComputeValue implements MethodReplacer {public Object reimplement (Object o, Method m, Object[] args) throws Throwable {/ bean的定义如下:
String
本章的例⼦可以参考bean-di中的bean-di部分。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论