文档章节

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

Java3y
 Java3y
发布于 03/14 12:06
字数 2013
阅读 562
收藏 17
点赞 2
评论 6

前言

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

回顾以前对象依赖

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

直接new对象

  • 在最开始,我们是直接new对象给service的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



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方法给属性注入值
    1. 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的依赖关系就好了....在service中加入一个构造函数,参数就是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");

 

这里写图片描述

 

通过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>

  • 测试:

 

这里写图片描述

 

内部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>


  • 测试

 

这里写图片描述

 

我们发现这种思维方式和服务器访问的执行顺序是一样的,但是如果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还提供了自动装配的功能,能够非常简化我们的配置

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

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

XML配置根据名字

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


    <bean id="userDao" class="UserDao"/>

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

  • 测试

 

这里写图片描述

 

XML配置根据类型

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

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


    <bean id="userDao" class="UserDao"/>

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

  • 测试:

 

这里写图片描述

 

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

 

这里写图片描述

 

###使用注解来实现自动装配###

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

  • 可以在构造器上修饰
  • 也可以在setter方法上修饰
  • 来自java的@Inject的和@AutoWired有相同的功能

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

  • 测试代码
@Component
public class UserService {

    private UserDao userDao ;


    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

顺利拿到userDao的引用

 

这里写图片描述

 

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

在有两种方法(但我测试不出来,如果会的请在评论去告诉我.....)

  • 第一种(测试不出来)

import org.springframework.context.annotation.Bean;

@org.springframework.context.annotation.Configuration
public 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.Configuration
public class Configuration {

    @Bean()
    public UserDao userDao() {

        return new UserDao();
    }

    @Bean
    public UserService userService(UserDao userDao) {

        //通过构造函数依赖注入
        return new UserService(userDao);
    }

}

 

这里写图片描述

 

  • 如果我直接通过构造器传入的话,那么报错了

import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean;

@org.springframework.context.annotation.Configuration
public class Configuration {

    @Bean()
    public UserDao userDao() {

        return new UserDao();
    }

    @Bean(autowire = Autowire.BY_TYPE)
    public UserService userService(UserDao userDao) {

        return new UserService(userDao);
    }

}

 

这里写图片描述

 

  • 我测试中只有通过这种方法才能拿到userDao的引用。
public class Configuration {

    @Bean()
    public UserDao userDao() {

        return new UserDao();
    }

    @Bean(autowire = Autowire.BY_TYPE)
    public UserService userService() {

        return new UserService(userDao());
    }

}


 

这里写图片描述

 

当然了,最简单直观的方法还有一种:在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.Configuration
public 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;
    }

}

 

这里写图片描述

 

最后

扩展阅读:

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

 

© 著作权归作者所有

共有 人打赏支持
Java3y
粉丝 278
博文 155
码字总数 478947
作品 0
广州
程序员
加载中

评论(6)

Java3y
Java3y

引用来自“iafdn”的评论

首先感谢作者提供这文章,我在看的时候发现有“serice”这个单词,不知道是作者有意为之还是写漏了一个"v"?
写漏了,不好意思哦:joy:~~~感谢指正
iafdn
iafdn
首先感谢作者提供这文章,我在看的时候发现有“serice”这个单词,不知道是作者有意为之还是写漏了一个"v"?
Java3y
Java3y

引用来自“程序小白白”的评论

通俗易懂, 很感谢
:grin:感谢支持
Java3y
Java3y

引用来自“小猎人”的评论

温故而知新:relaxed:
:grimacing:
程序小白白
程序小白白
通俗易懂, 很感谢
小猎人
小猎人
温故而知新:relaxed:
Spring IOC知识点一网打尽!

前言 只有光头才能变强 回顾前面: 给女朋友讲解什么是代理模式 包装模式就是这么简单啦 单例模式你会几种写法? 工厂模式理解了没有? 在刷Spring书籍的时候花了点时间去学习了单例模式和工...

Java3y ⋅ 05/22 ⋅ 0

第一章:Spring Boot 解决了什么问题?

spring4推出前存在的问题: 1、大量的xml文件,配置相当繁琐 2、整合第三方框架的配置问题 3、低效的开发效率和部署效率等问题 Spring Boot是什么? Spring Boot 伴随spring4.0诞生 Spring B...

刘祖鹏 ⋅ 05/15 ⋅ 0

Spring MVC 到 Spring BOOT的简化之路

背景 从Servlet技术到Spring和Spring MVC,开发Web应用变得越来越简捷。但是Spring和Spring MVC的众多配置有时却让人望而却步,相信有过Spring MVC开发经验的朋友能深刻体会到这一痛苦。因为...

临江仙卜算子 ⋅ 05/09 ⋅ 0

Spring Boot干货系列: (一)优雅的入门篇

     前言   Spring一直是很火的一个开源框架,在过去的一段时间里,Spring Boot在社区中热度一直很高,所以决定花时间来了解和学习,为自己做技术储备。   正文   首先声明,Spr...

后端编程嘟 ⋅ 2017/03/12 ⋅ 0

spring整合kaptcha验证码

kaptcha简介: kaptcha 是一个很有用的验证码生成工具,由于它有许多可配置项,所以用它可以简单快捷的生成各式各样的验证码。 开发工具及使用的核心技术: 1、eclipse 2、mybatis 3、spring ...

贪挽懒月 ⋅ 05/09 ⋅ 0

简化SSM搭建详细分析配置

一直使用SSH2 和 spring boot,最近换工作,使用新框架SpringMVC,带着SSH2的思路学习SpringMVC还是挺容易的,下面分享一下SSM的搭建 总体来说搭建SSM分五步 一:创建maven工程 这里是创建m...

红尾巴的猪 ⋅ 2017/11/10 ⋅ 0

Spring--Redis入门集成配置

一、什么是Redis? 这两年对于 NoSQL(not only SQL) 的使用已经越加频繁,所以对于Redis是什么我们也不会太过陌生。简单来说,Redis就是一个开源的,Key-Value数据库。它的存在主要是为了减少...

ge洋 ⋅ 04/17 ⋅ 0

spring session整合

花了大半天时间,解决了springMVC项目增加spring-session共享session报了异常 前情 项目做了前后端分离,springMVC项目部署在三台tomcat上,前端部署在另三台tomcat上,然后HA做了分发处理,...

jia程序员 ⋅ 05/23 ⋅ 0

Spring Cloud构建微服务架构服务注册与发现

Spring Cloud简介 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中涉及的配置管理、服务发现、断路器、智能路由、微代理、控制总线、全局锁、决策竞选、...

明理萝 ⋅ 06/11 ⋅ 0

项目中SpringMVC、Spring和Struts的区别讲解

导读:近期做到的项目中,用到的框架师SSM(SpringMVC+Spring+Mybatis),那么在这之前用过SSH,这里主要是区分一下SpringMVC和Struts,但是由于SpringMVC和Spring真的也挺容易迷糊的,所以,...

yiguang_820的博客 ⋅ 2017/12/11 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Linux kernel脉络和主干总结

写在前面 前人常说,对Linux操作系统/内核的理解,是计算机行业从业者的内功,决定了你在技术领域想走多远。但内核的庞大以及学习曲线之陡峭,总让我在学习途中觉得犹如“管中窥豹”。 随着工...

Markz0928 ⋅ 15分钟前 ⋅ 0

在gcc中使用intel风格的内联汇编

很简单,内联汇编使用asm(“.intel_syntax noprefix/n”)声明一下,以后的内联汇编就可以用intel风格了,构建可执行文件时给gcc加上-masm=intel参数。 先写一个小程序测试一下: [cpp] view...

simpower ⋅ 26分钟前 ⋅ 0

NIO 之 ByteBuffer实现原理

相关文章 BIO、NIO、AIO 内部原理分析 NIO 之 Selector实现原理 NIO 之 Channel实现原理 前言 Java NIO 主要由下面3部分组成: Buffer Channel Selector 在传统IO中,流是基于字节的方式进行...

轨迹_ ⋅ 35分钟前 ⋅ 0

Jenkins docker权限问题

环境Ubuntu Server 工具 jenkins-war:2.89.2 报错信息 Cannot connect to the Docker daemon. Is the docker daemon running on this host?Build step 'Execute shell' marked build as fai......

Pulsar-V ⋅ 35分钟前 ⋅ 0

180621-一个简单的时间窗口设计与实现

如何设计一个计数的时间窗口 时间窗口,通常对于一些实时信息展示中用得比较多,比如维持一个五分钟的交易明细时间窗口,就需要记录当前时间,到五分钟之前的所有交易明细,而五分钟之前的数...

小灰灰Blog ⋅ 58分钟前 ⋅ 0

Android之Dalvik、ART、JIT、AOT

Android之Dalvik、ART、JIT、AOT 本文内容:Dalvik、ART、JIT、AOT之间关系 本文定位:知识记录 学习过程记录,加深理解,提升文字组合表达能力。也希望能给学习的同学一些灵感 本文整理于[...

lichuangnk ⋅ 今天 ⋅ 0

Thrift RPC实战(五) thrift连接池

Thrift本身没有提供连接池,我们可以用Apache Commons Pool2来实现一个 一、定义对象工厂 BasePooledObjectFactory<T> extends BaseObject implements PooledObjectFactory<T> public class......

lemonLove ⋅ 今天 ⋅ 0

git 命令简写

简写 命令 g git gst git status gd git diff gdc git diff --cached gdv git diff -w "$@" | view - gl git pull gup git pull --rebase gp git push gc git commit -v gc! git commit -v ......

charley158 ⋅ 今天 ⋅ 0

Java中的锁使用与实现

1.Lock接口 锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源。 在Lock出现之前,java程序是靠synchronized关键字实现锁功能的,而Java SE5之后,...

ZH-JSON ⋅ 今天 ⋅ 0

Intellij IDEA神器常用技巧四-类和方法注释模板设置

IDEA自带的注释模板不是太好用,我本人到网上搜集了很多资料系统的整理了一下制作了一份比较完整的模板来分享给大家,我不是专业玩博客的,写这篇文章只是为了让大家省事。 这里设置的注释模...

Mkeeper ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部