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 String ultimateAnswer;public ExampleBean(int years, String ultimateAnswer) {this.years = years;this.ultimateAnswer = ultimateAnswer;}} 

该Bean有一个两个参数的构造函数,那么怎么注入这些参数呢?

有三种方法。

方法1:按构造函数的类型匹配:

这里通过指定参数的类型,即可以指定哪个参数是years,哪个参数是ultimateAnswer。

方法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 Universe, and Everythingprivate String ultimateAnswer;@ConstructorProperties ({"years", "ultimateAnswer"})public ExampleBeanWithConstructorProperties (int years, String ultimateAnswer) {this.years = years;this.ultimateAnswer = ultimateAnswer;}}

基于Setter的注入

Setter注入主要用来无参构造器或者获得对象实例之后才设置对象的属性。下面是Setter的例子:

public class SimpleMovieLister {// the SimpleMovieLister has a dependency on the MovieFinderprivate MovieFinder movieFinder;// a setter method so that the Spring container can inject a MovieFinderpublic void setMovieFinder (MovieFinder movieFinder) {this.movieFinder = movieFinder;}// business logic that actually uses the injected MovieFinder is omitted...}

对于的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= com.mysql.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 类型的属性和参数。 下面是个例子:

 administrator@example.org support@example.org development@example.org"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种模式:

76f5ec65e933f6c982974dc731bcd08a.png

自动注入的限制和缺陷

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

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 MovieFinderprivate MovieFinder movieFinder;// a setter method so that the Spring container can inject a MovieFinderpublic 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 CommandCommand command = createCommand();// set the state on the (hopefully brand new) Command instancecommand.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 interfaceAsyncCommand command = createCommand();return null;}// okay... but where is the implementation of this method?public abstract AsyncCommand createCommand();}

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

public class AsyncCommand {}

下面是XML配置文件:

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 resultString input = (String) args[0];return "def";}}

bean的定义如下:

String

本章的例子可以参考bean-di中的bean-di部分。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/396243.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#学习笔记四: C#3.0自动属性匿名属性及扩展方法

前言 这一章算是看这本书最大的收获了, Lambda表达式让人用着屡试不爽, C#3.0可谓颠覆了我们的代码编写风格. 因为Lambda所需篇幅挺大, 所以先总结C#3.0智能编译器给我们带来的诸多好处, 下一遍会单独介绍Lambda表达式. 这篇主要包括的内容有: 自动属性,隐式类型,对象集合初始化…

mongdb集群3.4 shard 模式

从图中可以看到有四个组件&#xff1a;mongos、config server、shard、replica set。mongos&#xff1a;数据库集群请求的入口&#xff0c;所有的请求都通过mongos进行协调&#xff0c;不需要在应用程序添加一个路由选择器&#xff0c;mongos自己就是一个请求分发中心&#xff…

alpha值计算 qcolor_量化交易与机器学习(四):如何研究alpha因子

算法交易策略由指示何时购买或出售资产以产生相对于基准&#xff08;例如指数&#xff09;的较高回报的信号驱动。 资产回报率中未通过暴露于该基准而无法解释的部分称为alpha&#xff0c;因此旨在产生这种不相关收益的信号也称为alpha因子。本章主要介绍alpha因子一、从数据到…

项目启动及需求分析(靳嘉豪、胡新宇、李晨曦、杨航、李瑶)团队作业

&#xff08;1&#xff09; 这次团队我们给我们团队起的名字是&#xff1a;桥上吊刀刀倒吊着 队员分别为&#xff1a;靳嘉豪、胡新宇、李晨曦、李瑶、杨航。 队训为&#xff1a;黑化肥挥发发灰会挥发。 胡新宇&#xff1a;http://www.cnblogs.com/hxy94264/ 靳嘉豪&#xff1a;…

20155229 实验一《Java开发环境的熟悉》实验报告

20155229 实验一《Java开发环境的熟悉》实验报告 实验内容 1.使用JDK编译、运行简单的Java程序&#xff1b; 2.使用Idea 编辑、编译、运行、调试Java程序。 实验步骤 &#xff08;一&#xff09;命令行下Java程序开发 输入 mkdir 20155229命令建立实验目录&#xff0c;用ls查看…

PHP代码20个实用技巧(转)

这些技巧特别是封装的&#xff0c;相对路径的还是挺好的&#xff0c;本身来自微信公众号&#xff0c;但是我担心以后删除&#xff0c;所以在我的博客上备份一下&#xff08;微信公众号为:菜鸟教程&#xff09; 在这篇文章中我们将看看一些关于PHP开发有用的提示和技巧&#xff…

python基础数据类型的相关知识点

1、字符串的函数join >>> s "Hello" >>> s1 s.join("你好")#将字符串Hello插入到你好中 >>> s1 你Hello好 >>> s2 "Tanxu".join("你好吗")#将字符串Tanxu插入到你好吗中 >>> s2 你Ta…

最长无重复字符子串?

2019独角兽企业重金招聘Python工程师标准>>> 题目要求&#xff1a; 给定一个字符串S&#xff0c;在该字符串中找到一个最长的没有重复字符的子串。 转载于:https://my.oschina.net/datacube/blog/875545

selenium框架安装及webdriver安装

本文介绍的是selenium安装及webdriver安装、小实例 1、selenium介绍 selenium是一个用于web应用程序测试的工具。 Selenium测试直接运行在浏览器&#xff0c;就向真正的用户操作一样。 支持的浏览器包括IE(7,8,9,10,11),Mazilla Firefox,Safari,Google Chrome,OperaL浏览器 这个…

突然想到了王自如

刚刚不知道为什么突然想到了王自如。可能是因为下午在腾讯视频首页看到了老罗罗永浩的一个访谈节目&#xff0c;然后神经元一短路的原因吧。 想到王自如不禁又联想到了王自如和罗永浩的那场著名的撕逼之战。场面上王自如是被罗老师教做人的一个结果。然后就很长时间没有听到关于…

UOJ Test Round 3

A.几何冲刺 感觉自己的智商爆炸。 显然是按照极角序排列之后依次加点&#xff0c;判断是否有点。 保证一个点在两个角的范围内就OK了啊&#xff0c;想了半天叉积。。。 #include "triangles.h" #include <bits/stdc.h> #define for1(a,b,i) for(int ia,end_b;i…

PPP认证方式pap chap chap2

2019独角兽企业重金招聘Python工程师标准>>> PPP点到点协议&#xff08;Point to Point Protocol&#xff0c;PPP&#xff09;是IETF&#xff08;Internet Engineering Task Force&#xff0c;因特网工程任务组&#xff09;推出的点到点类型线路的数据链路层协议。它…

Nexus-配置vPC 实验三

配置EvPC&#xff08;增强的vPC&#xff09;&#xff0c;下面两个FEX可以同时被两个N5K管理。注意&#xff1a;FEX只支持静态的Channel-group&#xff08;mode on&#xff09; N5K-1配置&#xff1a;配置FEXN5K-1&#xff08;config&#xff09;#feature fexN5K-1&#xff08;c…

python现在时间 命令,Python 日期格式和时间以及当前时间和时间戳

Python 程序在运行的时候可能需要获得当前的时间。在这个时候我们需要导入 datetime 包。获得当前时间例如&#xff0c;可以使用下面的代码获得当前的日期。today datetime.date.today()print("Todays date:", today)在上面的代码中&#xff0c;将会输出&#xff1a…

go grpc 深入笔记

为什么80%的码农都做不了架构师&#xff1f;>>> grpc 深入 生命周期 grpc 的生命周期由4种请求的方式不同而不同&#xff1a;(详细查看router示例) 普通rpc: 客户端发送请求&#xff0c;通知服务端调用rpc服务&#xff0c;服务端返回请求&#xff0c;如果状态"…

RSA加密算法简单分析

预备知识 1&#xff09;RSA是第一个比较完善的公开密钥算法&#xff0c;它既能用于加密&#xff0c;也能用于数字签名。RSA以它的三个发明者Ron Rivest, Adi Shamir, Leonard Adleman的名字首字母命名&#xff0c;这个算法经受住了多年深入的密码分析&#xff0c;虽然密码分析者…

Linux 小笔记

1、查看linux 版本 按ctrlshiftt 快捷键&#xff0c;打开终端&#xff0c;输入sudo uname --m &#xff0c;按下enter 如果显示i686,你安装了32位操作系统 如果显示 x86_64&#xff0c;你安装了64位操作系统 转载于:https://www.cnblogs.com/1995hxt/p/5436683.html

不会发布npm包?进来看看?

前言 npm(Node Package Manager)&#xff0c;一个Node的包管理器&#xff0c;平时我们常用的公共模块&#xff08;插件&#xff09;或者叫做包大多都放在上面&#xff0c;所以接下来要封装的插件&#xff0c;我们就简单称它为npm包&#xff0c;本文从就从这个简单的例子开始&am…

Nova 组件详解 - 每天5分钟玩转 OpenStack(26)

本节开始&#xff0c;我们将详细讲解 Nova 的各个子服务。 前面架构概览一节知道 Nova 有若干 nova-* 的子服务&#xff0c;下面我们将依次学习最重要的几个。今天先讨论 nova-api 和 nova-conductor。 nova-api Nova-api 是整个 Nova 组件的门户&#xff0c;所有对 Nova 的请…

12_04_Linux软件管理之四yum

2019独角兽企业重金招聘Python工程师标准>>> RPM安装&#xff1a; 二进制格式&#xff1a; 源程序--》编译--》二进制格式 有些特性是编译时选定的&#xff0c;如果编译时未选定此特性&#xff0c;将无法使用&#xff1b; rpm包的版本会落后于源码包&#xff0c;甚至…