Spring学习记录之依赖注入

问题1:

往一个类中传递数据的方式有哪些呢,其实,只有一种方式,即通过方法,但方法却有多种,一种是我们先前学到的通过set方法(普通方法),另一种则是通过构造方法的方式。

问题2:

依赖注入是描述了容器建立Bean与Bean之间的依赖关系的过程,那么如果Bean运行时需要的是字符串或者其他数据类型而非引用类型(Bean)呢?
那么关于依赖注入的类型也要分为两种,分别是引用类型(Bean)以及String,int等。

Setter方式依赖注入

先前,我们已经使用了set方法来注入引用类型:

<bean id="bookservice"  name="service,books1;bookl books" class="service.impl.BookServiceImpl" >
        <property name="bookdao" ref="bookdao"></property>
</bean>
public void setBookdao(BookDaoImpl bookdao) {
        this.bookdao=bookdao;
    }

那么,如果有多个引用类型呢,我们需要多个setter方法即可。
在BookServiceImpl中定义UserDao接口并实现

UserDao userdao;
public void setUserdao(UserDao userdao) {
        this.userdao = userdao;
 }

至于Spring的xml文件中只需要创建一个userdao,随后在bookservice中引用即可。

<bean id="userdao" class="dao.impl.UserDaoImpl" ></bean>
<bean id="bookservice"  name="service,books1;bookl books" class="service.impl.BookServiceImpl" >
        <property name="bookdao" ref="bookdao"></property>
        <property name="userdao" ref="userdao"></property>
</bean>

那么,该如何注入普通数据类型呢,我们在UserDaoImpl中定义两个私有成员变量:dataBaseNameconnectionNum

package dao.impl;
import dao.UserDao;
public class UserDaoImpl implements UserDao {
    private String dataBaseName;
    public void setDataBaseName(String dataBaseName) {
        this.dataBaseName = dataBaseName;
    }
    public void setConnectionNum(int connectionNum) {
        this.connectionNum = connectionNum;
    }
    private int connectionNum;
    @Override
    public void save() {
        System.out.print("userdao ..."+connectionNum+","+dataBaseName+"\n");
    }
}

随后在xml文件中注入属性值:使用property标签中的value属性来注入基本数据类型。

<bean id="userdao" class="dao.impl.UserDaoImpl" >
        <property name="connectionNum" value="10"></property>
        <property name="dataBaseName" value="mysql"></property>
</bean>

运行结果如下:

在这里插入图片描述

构造器方式依赖注入

接下来,上面是通过setter方法来进行依赖注入,另一种方法则是通过构造方法的形式进行依赖注入,事实上,两种写法很相似,但由于采用构造方法进行依赖注入时会有些许问题,因此我们大多采用setter方法来进行依赖注入。

在这里插入图片描述

在这里插入图片描述
由于构造器传参的方式要求Spring中属性的name必须与构造函数中的形参保持一致,因此具有一定的耦合度,这就导致Spring中提供了根据type类型与index属性来进行注入,但依旧很不方便,因此我们多采用Setter方法的方式进行注入。然而,仍存在些许情况我们需要使用构造器注入的方式:

在这里插入图片描述

依赖自动装配

前面已经介绍了两种依赖注入方式,但这些都需要我们自己去写,那么,这个依赖注入的方法能够不写呢,当然可以,Spring由此提出了依赖自动装配。
IOC根据Bean所依赖的资源在容器中自动查找并注入到Bean的过程称为依赖自动装配。
有两种主要的自动装配方式,分别是按照类型装配以及按照类型装配,其中按照类型装配最为常用。
首先,在ServiceImpl中的set方法还是需要保留的,这也符合Spring的装配策略,保证不易出错。
按名称装配:

package service.impl;

import dao.BookDao;
import dao.impl.BookDaoImpl;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import service.BookService;

public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
    BookDao bookdao;
    UserDao userdao;
    public void save() {
        System.out.print("执行service...\n");
        bookdao.save();
    }
    public void setBookdao(BookDaoImpl bookdao) {
        this.bookdao=bookdao;
    }
}

可以看到使用按名称自动装配时只需要使用autowire属性即可,这里的名称值得是在service中定义的成员变量bookdao,事实上,其真正对应的是set方法去掉set后第一个字母小写的名称即bookdao。

<bean id="bookservice" class="service.impl.BookServiceImpl" autowire="byName"></bean>

而按类型装配则更为简单了,它甚至都不需要依赖类有名字,会装配所有需要的,符合的Bean,这种也是最常用的。注意:里面对应的setter方法是需要保留的。

<bean id="bookdao" class="dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"></bean>
<bean  class="dao.impl.UserDaoImpl" >
        <property name="connectionNum" value="10"></property>
        <property name="dataBaseName" value="mysql"></property>
</bean>
<bean id="bookservice" class="service.impl.BookServiceImpl" autowire="byType"></bean>

在这里插入图片描述

集合注入

package dao.impl;
import dao.OrderDao;
import java.util.*;
public class OrderDaoImpl implements OrderDao {
    private List<String> list;
    private Map<String,String> map;
    private Set<String> set;
    private int[] array;
    public void setList(List<String> list) {
        this.list = list;
    }
    public void setMap(Map<String, String> map) {
        this.map = map;
    }
    public void setSet(Set<String> set) {
        this.set = set;
    }
    public void setArray(int[] index) {
        this.array = index;
    }
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
    private Properties properties;
    @Override
    public void show() {     System.out.print(Arrays.toString(array)+"\n"+map+"\n"+set+"\n"+list+"\n"+properties+"\n");
    }
}
<bean id="orderdao" class="dao.impl.OrderDaoImpl"> 
    <property name="map">
        <map>
            <entry value="100" key="apple"></entry>
            <entry value="40" key="orange"></entry>
            <entry value="130" key="dog"></entry>
        </map>
    </property>
    <property name="array">
        <array>
            <value>100</value>
            <value>200</value>
        </array>
    </property>
    <property name="list">
        <list>
            <value>dog</value>
            <value>cat</value>
        </list>
    </property>
    <property name="set">
        <set>
            <value>100</value>
            <value>100</value>
            <value>200</value>
        </set>
    </property>
    <property name="properties">
        <props>
            <prop key="country">china</prop>
            <prop key="city">beijing</prop>
        </props>
    </property>
</bean>

运行结果:

在这里插入图片描述

数据源等对象(第三方资源)管理

先前的都是我们对自己创建的对象Bean进行管理,那么对于一些第三方资源如何管理呢?
这里我们以数据库连接池c3p0为例,首先在pom.xml文件中加入c3p0的坐标:

<dependency>
      <groupId>c3p0</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.1.2</version>
</dependency>

随后在IOC容器中配置Bean,我们可以在浏览器中搜索c3p0的连接池Bean使用哪个类进行创建,随后我们进入该类中,按Alt+7调出该类的所有方法,从而确定我们是使用setter还是构造函数的方式来创建Bean。

 <bean class="com.mchange.v2.c3p0.ComboPooledDataSource">
 </bean>

我们通过查看其方法发现其提供的是通过setter方法来传递参数,我们将其配置完成。

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="jdbcUrl" value="jdbc\:mysql\:///ssm_takeout?characterEncoding=utf-8"/>
        <property name="user" value="root"/>
        <property name="password" value="root"/>
</bean>

随后运行一下:

ClassPathXmlApplicationContext ctx=new ClassPathXmlApplicationContext("applicationContext.xml");
DataSource dataSource= (DataSource) ctx.getBean("dataSource");
System.out.print(dataSource);

在这里插入图片描述
但是,我们直接将配置信息写在IOC容器中是不合适的,我们应该使用Properties文件来读取到Bean中进而生成配置。那么如何使用Spring加载外部文件呢?Spring 使用开启命名空间的方式来加载外部文件。
在头文件上加上下面三句代码:
1.开启context命名空间
在这里插入图片描述

<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
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
        "
>

随后使用context命名空间加载properties文件并通过属性占位符$读取数据
这里只要我们使用context加载完文件后,那么${jdbc.driver}便可以在整个IOC容器中使用。

<context:property-placeholder location="db.properties"/>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
</bean>

此外,需要注意的是,在加载文件时,如果properties文件中的变量与一些系统变量重复了,那么由于系统变量优先级较高,则会覆盖我们设置的变量,此时,我们只需要在添加一个属性system-properties-mode="NEVER"即可,代表不加载系统变量。

 <context:property-placeholder location="db.properties" system-properties-mode="NEVER"/>

同时,如果想要加载多个properties文件,只需要在location属性中通过逗号连接即可。

<context:property-placeholder location="db.properties,db.properties1" system-properties-mode="NEVER"/>

但这样的加载方式也太过麻烦,我们可以使用*.properties来匹配所有的配置文件。

<context:property-placeholder location="*.properties" system-properties-mode="NEVER"/>

但最规范的格式应加上classpath

<context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>

但这种方式只能在自己的项目中读取,要想在引用的jar包中读取则可使用:

<context:property-placeholder location="classpath*:db.properties" system-properties-mode="NEVER"/>

在这里插入图片描述

容器

这里我们对容器内容进行补充:其中第一种是根据类路径加载配置文件,第二种则是根据绝对路径加载配置配件,我们多采用第一种。
在这里插入图片描述

在这里插入图片描述
需要注意的是,创建容器的方式有两种分别是通过BeanFactory与ApplicationContext,我们常用的是后者,其加载方式是立即加载,即在创建容器时便将Bean创建好了,而还有一种方式则是 在我们需要才创建Bean,称为延迟加载,如何实现呢?加上lazy-init属性即可

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" lazy-init="true">

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 29
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

彭祥.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值