Spring依赖注入

常的java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依赖类不由程序员实例化,而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类中。依赖注入的另一种说法是“控制反转”,通俗的理解是:平常我们new一个实例,这个实例的控制权是我们程序员,而控制反转是指new实例工作不由我们程序员来做而是交给spring容器来做。

构造函数注入

在bean标签的内部使用constructor-arg标签就可以进行构造函数注入了。

constructor-arg标签的属性:

  • type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型
  • index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值,索引的位置从0开始
  • name:用于给指定构造函数中指定名称的参数赋值
  • value:用于提供基本类型和String类型的数据
  • ref:用于指定其他的bean类型数据,就是在IOC容器中出现过的bean对象

    bean.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="accountService" class="com.sks.service.imp.AccountServiceImpl">
<constructor-arg type="java.lang.String" value="张三"/>
<constructor-arg index="1" value="20"/>
<constructor-arg name="birthday" ref="birthday"/>
</bean> <bean id="birthday" class="java.util.Date"/> </beans>

AccountServiceImpl 类

public class AccountServiceImpl implements AccountService {

    private String name;
private Integer age;
private Date birthday; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} public Date getBirthday() {
return birthday;
} public void setBirthday(Date birthday) {
this.birthday = birthday;
} @Override
public String toString() {
return "AccountServiceImpl{" +
"name='" + name + '\'' +
", age=" + age +
", birthday=" + birthday +
'}';
} public AccountServiceImpl(String name, Integer age, Date birthday) {
System.out.println("含参的构造方法被调用了");
this.name = name;
this.age = age;
this.birthday = birthday;
} public AccountServiceImpl() {
System.out.println("构造方法调用");
} @Override
public int addMoney(int money) {
System.out.println("向账户中加钱:" + money);
return 0;
} @Override
public void saveAccount(Account account) {
System.out.println("saveAccount方法执行了");
}
}

测试

	/**
* 测试构造函数注入
*/
@Test
public void test8() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:bean.xml");; AccountService accountService = (AccountService) applicationContext.getBean("accountService"); System.out.println(accountService.toString());
}

运行测试以后,可以在控制台看到以下内容:

优点:在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。

缺点:改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据也必须提供。

setter方法注入

在bean标签内部使用property标签进行配置。

property标签的属性:

  • name:用于指定注入时所调用的set方法名称
  • value:用于提供基本类型和String类型的数据
  • ref:用于指定其他的bean类型数据

这里面我们注入了基本类型、包装类型、日期类型数据。

AccountServiceImpl 类

public class AccountServiceImpl implements AccountService {

    private String name;
private Integer age;
private Date birthday; public String getName() {
return name;
} public void setName(String name) {
System.out.println("给name设置值");
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
System.out.println("给age设置值");
this.age = age;
} public Date getBirthday() {
return birthday;
} public void setBirthday(Date birthday) {
System.out.println("给birthday设置值");
this.birthday = birthday;
} @Override
public String toString() {
return "AccountServiceImpl{" +
"name='" + name + '\'' +
", age=" + age +
", birthday=" + birthday +
'}';
} public AccountServiceImpl(String name, Integer age, Date birthday) {
System.out.println("含参的构造方法被调用了");
this.name = name;
this.age = age;
this.birthday = birthday;
} public AccountServiceImpl() {
System.out.println("构造方法调用");
} @Override
public int addMoney(int money) {
System.out.println("向账户中加钱:" + money);
return 0;
} @Override
public void saveAccount(Account account) {
System.out.println("saveAccount方法执行了");
}
}

bean.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="accountService" class="com.sks.service.imp.AccountServiceImpl">
<!--注入基本类型、包装类型、日期类型数据-->
<property name="age" value="22"/>
<property name="name" value="李四"/>
<property name="birthday" ref="birthday"/>
</bean> <bean id="birthday" class="java.util.Date"/>
</beans>

测试

    /**
* 测试setter方法注入
*/
@Test
public void test9() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:bean.xml");; AccountService accountService = (AccountService) applicationContext.getBean("accountService"); System.out.println(accountService.toString());
}

运行测试以后,可以在控制台看到以下内容:

优势:创建对象时没有明确的限制,可以直接使用默认构造函数。

缺点:如果又某个成员必须有值,则获取对象有可能是set方法没有执行。

对集合类型数据进行注入

AccountService2Impl 类

public class AccountService2Impl implements AccountService2 {

    private String[] myStrs;

    private List<String> myList;

    private Set<String> mySet;

    private Map<String, String> myMap;

    private Properties myProps;

    public String[] getMyStrs() {
return myStrs;
} public void setMyStrs(String[] myStrs) {
this.myStrs = myStrs;
} public List<String> getMyList() {
return myList;
} public void setMyList(List<String> myList) {
this.myList = myList;
} public Set<String> getMySet() {
return mySet;
} public void setMySet(Set<String> mySet) {
this.mySet = mySet;
} public Map<String, String> getMyMap() {
return myMap;
} public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
} public Properties getMyProps() {
return myProps;
} public void setMyProps(Properties myProps) {
this.myProps = myProps;
} @Override
public String toString() {
return "AccountService2Impl{" +
"myStrs=" + Arrays.toString(myStrs) +
", myList=" + myList +
", mySet=" + mySet +
", myMap=" + myMap +
", myProps=" + myProps +
'}';
} }

bean.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="accountService2" class="com.sks.service.imp.AccountService2Impl">
<property name="myStrs">
<array>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property> <property name="myList">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
</list>
</property> <property name="mySet">
<set>
<value>set1</value>
<value>set2</value>
<value>set3</value>
</set>
</property> <property name="myProps">
<props>
<prop key="name">柯森</prop>
<prop key="age">23</prop>
</props>
</property> <property name="myMap">
<map>
<entry key="key1" value="value1"/>
<entry key="key2" value="value2"/>
<entry key="key3">
<value>value3</value>
</entry>
</map>
</property>
</bean> </beans>

测试

    /**
* 测试注入复杂类型/集合数据
*/
@Test
public void test10() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:bean.xml"); AccountService2 accountService2 = (AccountService2) applicationContext.getBean("accountService2"); System.out.println(accountService2.toString());
}

运行测试以后,可以看到在控制台打印输出了以下内容:

这说明我们注入集合类型数据成功了。

注解注入

用于注入数据的注解

bean.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!--创建bean时要扫描的包-->
<context:component-scan base-package="com.sks"/> </beans>

AccountService4Impl 类

@Component
public class AccountService4Impl implements AccountService3 { @Autowired
private AccountDao accountDao; @Override
public void addMoney(int money) {
System.out.println("向账户中加钱....AccountService3Impl");
}
}

假设此时只有一个AccountDao的实现类,并且这个类也加上了@Repository注解,那么我们这样注入是可以成功的,但是如果容器中存在多个AccountDao的实现类,此时仅仅使用AccountDao是不能完成数据注入的,需要配合@Qualifier注解使用注入数据。

假设现有如下两个实现类,那我们应该怎么写才能成功注入数据?

@Component
public class AccountService4Impl implements AccountService3 { //错误写法,默认会去容器中查找名称为accountDao的bean
//@Autowired
//private AccountDao accountDao; //正确写法
//@Autowired
//private AccountDao accountDao1 //正确写法
//@Autowired
//private AccountDao accountDao1; //正确写法
@Autowired
@Qualifier("accountDao1")
private AccountDao accountDao; @Override
public void addMoney(int money) {
System.out.println("向账户中加钱....AccountService3Impl");
} }

测试

    @Test
public void test2() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:bean.xml");
AccountService4Impl accountService4 = (AccountService4Impl) applicationContext.getBean("accountService4Impl"); System.out.println("accountService4:" + accountService4);
}

@Value注解的基本使用

在使用@Value注入基本类型和String类型的数据时使用"#“号;使用@Value读取配置文件的值时需要使用”$"符号,同时使用@PropertySource注解指定配置文件的位置。

@Component
@PropertySource("classpath:db.properties")
public class AccountService4Impl implements AccountService3 { @Autowired
@Qualifier("accountDao1")
private AccountDao accountDao; //使用SPEL表达式只注入值
@Value("#{19 - 9}")
private int age; @Value("zhangsan")
private String name; //读取操作系统的名称
@Value("#{systemProperties['os.name']}")
private String osname; //读取数据库配置文件中的值
@Value("${password}")
private String password; @Override
public void addMoney(int money) {
System.out.println("向账户中加钱....AccountService3Impl");
} }

测试

    @Test
public void test2() {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:bean.xml");
AccountService4Impl accountService4 = (AccountService4Impl) applicationContext.getBean("accountService4Impl"); System.out.println("accountService4:" + accountService4 + " " + accountService4.getName() + " " + accountService4.getAge()); }

断点调试可以看到如下结果,说明我们使用@Value注入数据成功。

最后

欢迎关注公众号:前程有光,领取一线大厂Java面试题总结+各知识点学习思维导+一份300页pdf文档的Java核心知识点总结!

java开发两年,连Spring的依赖注入的方式都搞不清楚,你工作可能有点悬!的更多相关文章

  1. Spring学习--依赖注入的方式

    Spring 依赖注入: 属性注入(最常使用) 构造函数注入 工厂方法注入(很少使用,不推荐) 属性注入:通过 setter 方法注入 Bean 的属性值或依赖的对象 , 使用<property ...

  2. Spring学习(三)——Spring中的依赖注入的方式

    [前面的话] Spring对我太重要了,做个关于web相关的项目都要使用Spring,每次去看Spring相关的知识,总是感觉一知半解,没有很好的系统去学习一下,现在抽点时间学习一下Spring.不知 ...

  3. Spring的依赖注入(DI)三种方式

    Spring依赖注入(DI)的三种方式,分别为: 1.  接口注入 2.  Setter方法注入 3.  构造方法注入 下面介绍一下这三种依赖注入在Spring中是怎么样实现的. 首先我们需要以下几个 ...

  4. Spring IOC 依赖注入的两种方式XML和注解

    依赖注入的原理 依赖注入的方式---XML配置 依赖注入的方式---注解的方式 Spring 它的核心就是IOC和AOP.而IOC中实现Bean注入的实现方式之一就是DI(依赖注入). 一 DI的原理 ...

  5. 在ABAP里模拟实现Java Spring的依赖注入

    Dependency Injection- 依赖注入,在Java Spring框架中有着广泛地应用.通过依赖注入,我们不必在应用代码里繁琐地初始化依赖的资源,非常方便. 那么ABAP能否从语言层面上也 ...

  6. java框架篇---spring IOC依赖注入

    spring依赖注入的方式有4种 构造方法注入 属性注入 工厂注入 注解注入 下面通过一个实例统一讲解: User.java package com.bjsxt.model; public class ...

  7. spring的依赖注入的最常见的两种方法

    package com.lsz.spring.action; public class User { /** * set注入 */ private String username; public vo ...

  8. Spring系列之依赖注入的方式

    一.依赖注入方式 对于spring配置一个bean时,如果需要给该bean提供一些初始化参数,则需要通过依赖注入方式,所谓的依赖注入就是通过spring将bean所需要的一些参数传递到bean实例对象 ...

  9. Spring笔记——依赖注入

    依赖注入有三种方式: 1. 使用构造器注入  2. 使用属性setter方法注入 3. 使用Field注入(用于注解方式) 注入依赖对象可以采用手工装配或自动装配,在实际应用中建议使用手工装配,因为自 ...

随机推荐

  1. VScode如何配置c/c++运行环境

    vscode如何配置c/c++环境 下载 Mingw 参考链接:https://blog.csdn.net/jiqiren_dasheng/article/details/103775488 笔者下载 ...

  2. 基于Python与命令行人脸识别项目(系列二)

    接着系统一,继续开始我们face_recognition. Python 模块:face_recognition 在Python中,你可以导入face_recognition模块,调用丰富的API接口 ...

  3. D. Road to Post Office 解析(思維)

    Codeforce 702 D. Road to Post Office 解析(思維) 今天我們來看看CF702D 題目連結 題目 略,請直接看原題. 前言 原本想說會不會也是要列式子解或者二分搜,沒 ...

  4. Luogu P4234 最小差值生成树

    题意 给定一个 \(n\) 个点 \(m\) 条边的有权无向图,求出原图的一棵生成树使得该树上最大边权与最小边权的差值最小. \(\texttt{Data Range:}1\leq n\leq 5\t ...

  5. mq_open失败,Invalid argument

    经四处查找,终于发现原因: (1)attr.mq_maxmsg 不能超过文件 /proc/sys/fs/mqueue/msg_max 中的数值,我的机器上面是10. (2)attr.mq_msgsiz ...

  6. Java学习的第三十五天

    1. 例1.1 例1.2 例1.3 例1.4 2.不知道为什么con的时候错误需要加入 3.明天继续写例题

  7. 循序渐进VUE+Element 前端应用开发(25)--- 各种界面组件的使用(1)

    在我们使用Vue+Element开发前端的时候,往往涉及到很多界面组件的使用,其中很多直接采用Element官方的案例即可,有些则是在这个基础上封装更好利用.更少代码的组件:另外有些则是直接采用第三方 ...

  8. 从入门到掌握 - 系统学习shell语言

    简介 什么是 shell Shell是一种程序或命令行解释程序,用于解释用户直接输入的用户命令或从文件中读取的用户命令,然后将 它们传递给操作系统以进行操作或处理.要注意,这个过程是解释而不编译脚本, ...

  9. 这么设置Intellij IDEA,据说效率还不错~

    显示工具条 (1)效果图 (2)设置方法 标注1:View–>Toolbar 标注2:View–>Tool Buttons 设置鼠标悬浮提示 (1)效果图 (2)设置方法File–> ...

  10. P2937 [USACO09JAN]Laserphones S

    题意描述 [USACO09JAN]Laserphones S 学过物理的同学都知道这种镜子是可以把光线旋转 90 度的. 那么显然就是要求添加镜子的最小个数. 貌似题目漏了一句就是题目保证有解的情况. ...