Spring【依赖注入】就是这么简单

小编 2026-06-29 阅读:897 评论:0
前言在Spring的第二篇中主要讲解了Spring Core模块的使用IOC容器创建对象的问题,...

前言

在Spring的第二篇中主要讲解了Spring Core模块的使用IOC容器创建对象的问题,Spring Core模块主要是解决对象的创建和对象之间的依赖关系,因此本博文主要讲解如何使用IOC容器来解决对象之间的依赖关系

回顾以前对象依赖

我们来看一下我们以前关于对象依赖,是怎么的历程

直接new对象

  • 在最开始,我们是直接new对象给serice的userDao属性赋值...
class  UserService{    UserDao userDao = new UserDao();}

写DaoFactory,用字符串来维护依赖关系

  • 后来,我们发现service层紧紧耦合了dao层。我们就写了DaoFactory,在service层只要通过字符串就能够创建对应的dao层的对象了。

  • DaoFactory

public class DaoFactory {    private static final DaoFactory factory = new DaoFactory();    private DaoFactory(){}    public static DaoFactory getInstance(){        return factory;    }    public <T> T createDao(String className,Class<T> clazz){        try{            T t = (T) Class.forName(className).newInstance();            return t;        }catch (Exception e) {            throw new RuntimeException(e);        }    }}
  • serivce
    private CategoryDao categoryDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.CategoryDAOImpl", CategoryDao.class);    private BookDao bookDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.BookDaoImpl", BookDao.class);    private UserDao userDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.UserDaoImpl", UserDao.class);    private OrderDao orderDao = DaoFactory.getInstance().createDao("zhongfucheng.dao.impl.OrderDaoImpl", OrderDao.class);

DaoFactory读取配置文件

  • 再后来,我们发现要修改Dao的实现类,还是得修改service层的源代码呀..于是我们就在DaoFactory中读取关于daoImpl的配置文件,根据配置文件来创建对象,这样一来,创建的是哪个daoImpl对service层就是透明的

  • DaoFactory
    ```java

public class DaoFactory {

private  UserDao userdao = null;private DaoFactory(){    try{        InputStream in = DaoFactory.class.getClassLoader().getResourceAsStream("dao.properties");        Properties prop = new Properties();        prop.load(in);                String daoClassName = prop.getProperty("userdao");        userdao = (UserDao)Class.forName(daoClassName).newInstance();            }catch (Exception e) {        throw new RuntimeException(e);    }}private static final DaoFactory instance = new DaoFactory();public static DaoFactory getInstance(){    return instance;}public UserDao createUserDao(){    return userdao;}

}

```

  • service
    UserDao dao = DaoFactory.getInstance().createUserDao();

Spring依赖注入

通过上面的历程,我们可以清晰地发现:对象之间的依赖关系,其实就是给对象上的属性赋值!因为对象上有其他对象的变量,因此存在了依赖...

Spring提供了好几种的方式来给属性赋值

  • 1) 通过构造函数
  • 2) 通过set方法给属性注入值
  • 3) p名称空间
  • 4)自动装配(了解)
  • 5) 注解

搭建测试环境

  • UserService中使用userDao变量来维护与Dao层之间的依赖关系
  • UserAction中使用userService变量来维护与Service层之间的依赖关系

  • userDao

public class UserDao {    public void save() {        System.out.println("DB:保存用户");    }}
  • userService
public class UserService {        private UserDao userDao;     public void save() {        userDao.save();    }}
  • userAnction
public class UserAction {    private UserService userService;    public String execute() {        userService.save();        return null;    }}

构造函数给属性赋值

其实我们在讲解创建带参数的构造函数的时候已经讲过了...我们还是来回顾一下呗..

我们测试service和dao的依赖关系就好了....在serice中加入一个构造函数,参数就是userDao

    public UserService(UserDao userDao) {        this.userDao = userDao;                //看看有没有拿到userDao        System.out.println(userDao);    }

applicationContext.xml配置文件

    <!--创建userDao对象-->    <bean id="userDao" class="UserDao"/>    <!--创建userService对象-->    <bean id="userService" class="UserService">        <!--要想在userService层中能够引用到userDao,就必须先创建userDao对象-->        <constructor-arg index="0" name="userDao" type="UserDao" ref="userDao"></constructor-arg>    </bean>
  • 测试:可以成功获取到userDao对象
        // 创建容器对象        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");        //得到service对象        UserService userService = (UserService) ac.getBean("userService");

Spring【依赖注入】就是这么简单


通过set方法给属性注入值

我们这里也是测试service和dao层的依赖关系就好了...在service层通过set方法来把userDao注入到UserService中

  • 为UserService添加set方法
public class UserService {    private UserDao userDao;    public void setUserDao(UserDao userDao) {        this.userDao = userDao;        //看看有没有拿到userDao        System.out.println(userDao);    }    public void save() {        userDao.save();    }}

applicationContext.xml配置文件:通过property节点来给属性赋值

  • 引用类型使用ref属性
  • 基本类型使用value属性
    <!--创建userDao对象-->    <bean id="userDao" class="UserDao"/>    <!--创建userService对象-->    <bean id="userService" class="UserService">        <property name="userDao" ref="userDao"/>    </bean>
  • 测试:

Spring【依赖注入】就是这么简单


内部Bean

我们刚才是先创建userDao对象,再由userService对userDao对象进行引用...我们还有另一种思维:先创建userService,发现userService需要userDao的属性,再创建userDao...我们来看看这种思维方式是怎么配置的:

applicationContext.xml配置文件:property节点内置bean节点

    <!--        1.创建userService,看到有userDao这个属性        2.而userDao这个属性又是一个对象        3.在property属性下又内置了一个bean        4.创建userDao    -->    <bean id="userService" class="UserService">        <property name="userDao">            <bean id="userDao" class="UserDao"/>        </property>    </bean>
  • 测试

Spring【依赖注入】就是这么简单

我们发现这种思维方式和服务器访问的执行顺序是一样的,但是如果userDao要多次被其他service使用的话,就要多次配置了...

p 名称空间注入属性值

p名称控件这种方式其实就是set方法的一种优化,优化了配置而已...p名称空间这个内容需要在Spring3版本以上才能使用...我们来看看:

applicationContext.xml配置文件:使用p名称空间

    <bean id="userDao" class="UserDao"/>        <!--不用写property节点了,直接使用p名称空间-->    <bean id="userService" class="UserService" p:userDao-ref="userDao"/>
  • 测试

Spring【依赖注入】就是这么简单


自动装配

Spring还提供了自动装配的功能,能够非常简化我们的配置

自动装载默认是不打开的,自动装配常用的可分为两种:

  • 根据名字来装配
  • 根据类型类装配

XML配置根据名字

applicationContext.xml配置文件:使用自动装配,根据名字

    <bean id="userDao" class="UserDao"/>    <!--        1.通过名字来自动装配        2.发现userService中有个叫userDao的属性        3.看看IOC容器中没有叫userDao的对象        4.如果有,就装配进去    -->    <bean id="userService" class="UserService" autowire="byName"/>
  • 测试

Spring【依赖注入】就是这么简单


XML配置根据类型

applicationContext.xml配置文件:使用自动装配,根据类型

值得注意的是:如果使用了根据类型来自动装配,那么在IOC容器中只能有一个这样的类型,否则就会报错!

    <bean id="userDao" class="UserDao"/>    <!--        1.通过名字来自动装配        2.发现userService中有个叫userDao的属性        3.看看IOC容器UserDao类型的对象        4.如果有,就装配进去    -->    <bean id="userService" class="UserService" autowire="byType"/>
  • 测试:

Spring【依赖注入】就是这么简单


我们这只是测试两个对象之间的依赖关系,如果我们有很多对象,我们也可以使用默认自动分配

Spring【依赖注入】就是这么简单


使用注解来实现自动装配

@Autowired注解来实现自动装配:

如果没有匹配到bean,又为了避免异常的出现,我们可以使用required属性上设置为false。【谨慎对待】

  • 测试代码

    @Componentpublic class UserService {private UserDao userDao ;@Autowiredpublic void setUserDao(UserDao userDao) {    this.userDao = userDao;}}

顺利拿到userDao的引用

Spring【依赖注入】就是这么简单

使用JavaConfig配置类实现对象依赖

  • 第一种(测试不出来)
import org.springframework.context.annotation.Bean;@org.springframework.context.annotation.Configurationpublic class Configuration {    @Bean()    public UserDao userDao() {        return new UserDao();    }    @Bean    public UserService userService() {        //直接调用@bean的方法        return new UserService(userDao());    }}

  • 第二种(测试不出来)
import org.springframework.context.annotation.Bean;@org.springframework.context.annotation.Configurationpublic class Configuration {    @Bean()    public UserDao userDao() {        return new UserDao();    }    @Bean    public UserService userService(UserDao userDao) {        //通过构造函数依赖注入        return new UserService(userDao);    }}

Spring【依赖注入】就是这么简单


  • 如果我直接通过构造器传入的话,那么报错了
import org.springframework.beans.factory.annotation.Autowire;import org.springframework.context.annotation.Bean;@org.springframework.context.annotation.Configurationpublic class Configuration {    @Bean()    public UserDao userDao() {        return new UserDao();    }    @Bean(autowire = Autowire.BY_TYPE)    public UserService userService(UserDao userDao) {        return new UserService(userDao);    }}

Spring【依赖注入】就是这么简单


  • 我测试中只有通过这种方法才能拿到userDao的引用。
public class Configuration {    @Bean()    public UserDao userDao() {        return new UserDao();    }    @Bean(autowire = Autowire.BY_TYPE)    public UserService userService() {        return new UserService(userDao());    }}

Spring【依赖注入】就是这么简单


当然了,最简单直观的方法还有一种:在UserService中加入setUser()方法,那么只要set进去就行了..

  • UserService
public class UserService {    private UserDao userDao ;    public UserService() {    }    public UserService(UserDao userDao) {    }    public void setUserDao(UserDao userDao) {        this.userDao = userDao;    }}
  • Config
import org.springframework.context.annotation.Bean;@org.springframework.context.annotation.Configurationpublic class Config1 {    @Bean(name = "userDao")    public UserDao userDao() {        return new UserDao();    }    @Bean(name="userService")    public UserService userService() {        UserService userService = new UserService();        userService.setUserDao(userDao());        return userService;    }}

Spring【依赖注入】就是这么简单


最后

扩展阅读:

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y

更多的文章可往:文章的目录导航
版权声明

本文仅代表作者观点,不代表百度立场。
本文系作者授权百度百家发表,未经许可,不得转载。

热门文章
  • 机房智能化温湿度解决方式之POE供电以太网温湿度传感器

    机房智能化温湿度解决方式之POE供电以太网温湿度传感器
    机房智能化温湿度解决方式之POE供电以太网温湿度传感器 北京盈创力和电子科技有限公司 智能型TCP网口温湿度记录仪 北京IP网络温湿度记录仪厂家,北京盈创力和 北京智能型TCP网口温湿度记录仪IP网络温湿度记录仪是一种新型的基于TCP/IP协议双绞线以太网标准温湿度采集模块,利用它可以实现现场温度值、相对湿度值的采集,同时利用其自身的RJ45通信接口可以方便地和机房监控主机或交换机集线器进行联网。 工作于-40℃~85℃工业级带...
  • Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering

    Sequential Monte Carlo Methods (SMC) 序列蒙特卡洛/粒子滤波/Bootstrap Filtering
    Problem Statement 我们考虑一个具有马尔可夫性质、非线性、非高斯的状态空间模型(State Space Model):对于一个时间序列上的观测结果{yt,t∈N}\\{ y_t , t \\in N \\}{yt​,t∈N},我们认为每个观测结果yty_tyt​的生成依赖于一个无法直接观察的隐变量xt∈{xt,t∈N}x_t \\in \\{x_t , t \\in N \\}xt​∈{xt​,t∈N},即:p(...
  • HTTP状态保持的原理

    HTTP状态保持的原理
    a)在用户登录之后,浏览器返回响应的时候会在响应中添加上cookieb)浏览器接收到cookie之后会自动保存c)当用户再次请求同一服务器中的其他网页的时候,浏览器会自动带上之前保存的cookied)服务接收到请求之后可以请 request 对象中取到cookie 判断当前用户是否登录  Http是无状态的,就是连接时数据互通,关闭后...
  • Hive 系统函数及示例

    Hive 系统函数及示例
    查看所有系统函数 show functions; 函数分类 内置函数【系统函数】 数学函数: floor、round、ceil、cos、log2等 字符串函数: length、reverse、trim、lower、get_json_object、repeat等 收集函数: size 转换函数: cast 日期函数: year、month、datediff、date、date_add等 条件函数: coalesce、case…w...
  • CSRF的原理和防范措施

    CSRF的原理和防范措施
    a)攻击原理:i.用户C访问正常网站A时进行登录,浏览器保存A的cookieii.用户C再访问攻击网站B,网站B上有某个隐藏的链接或者图片标签会自动请求网站A的URL地址,例如表单提交,传指定的参数iii.而攻击网站B在访问网站A的时候,浏览器会自动带上网站A的cookieiv.所以网站A在接收到请求之后可判断当前用户是登录状态,所以...
标签列表