前言

在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



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的依赖关系就好了....在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");


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

Spring【依赖注入】就是这么简单的更多相关文章

  1. Spring依赖注入 --- 简单使用说明

    Spring依赖注入 --- 简单使用说明 本文将对spring依赖注入的使用做简单的说明,enjoy your time! 1.使用Spring提供的依赖注入 对spring依赖注入的实现方法感兴趣 ...

  2. Spring依赖注入:注解注入总结

    更多11   spring   依赖注入   注解   java 注解注入顾名思义就是通过注解来实现注入,Spring和注入相关的常见注解有Autowired.Resource.Qualifier.S ...

  3. Spring 依赖注入,在Main方法中取得Spring控制的实例

    Spring依赖注入机制,在Main方法中通过读取配置文件,获取Spring注入的bean实例.这种应用在实训的时候,老师曾经说过这种方法,而且学Spring入门的时候都会先学会使用如何在普通的jav ...

  4. Spring依赖注入的三种方式

    看过几篇关于Spring依赖注入的文章,自己简单总结了一下,大概有三种方式: 1.自动装配 通过配置applicationContext.xml中的标签的default-autowire属性,或者标签 ...

  5. 二十7天 春雨滋润着无形 —Spring依赖注入

    6月11日,明确."夏条绿已密,朱萼缀明鲜.炎炎日正午,灼灼火俱燃." IT人习惯把详细的事物加工成的形状一致的类.正是这种一致,加上合适的规范.才干彰显对象筋道的牙感和bean清 ...

  6. SSH深度历险记(八) 剖析SSH核心原则+Spring依赖注入的三种方式

           于java发育.一类程序猿必须依靠类的其他方法,它是通常new依赖类的方法,然后调用类的实例,这样的发展问题new良好的班统一管理的例子.spring提出了依赖注入的思想,即依赖类不由程 ...

  7. SSH深度历险(八) 剖析SSH核心原理+Spring依赖注入的三种方式

           在java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依 ...

  8. Spring依赖注入原理分析

    在分析原理之前我们先回顾下依赖注入的概念: 我们常提起的依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念.具体含义是:当某个角色( ...

  9. Spring依赖注入servlet会话监听器

    Spring提供了一个 “ContextLoaderListener” 监听器,以使 Spring 依赖注入到会话监听器. 在本教程中,通过添加一个 Spring 依赖注入一个bean 到会话监听器修 ...

  10. Spring学习笔记——Spring依赖注入原理分析

    我们知道Spring的依赖注入有四种方式,各自是get/set方法注入.构造器注入.静态工厂方法注入.实例工厂方法注入 以下我们先分析下这几种注入方式 1.get/set方法注入 public cla ...

随机推荐

  1. NSData 与 NSString 的转化

    1 NSString * str = @"hello, world!"; 2 NSData * data = [str dataUsingEncoding:NSUTF8String ...

  2. 不受支持的URL Statue Code 1002

    1. 错误提示: Error description=Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" User ...

  3. PHP Extension开发(Zephir版本)

    上篇介绍了C语言开发PHP扩展的方法, 现在介绍使用Zephir开发扩展的方法. 关于Zephir需要简单介绍一下: Zephir 是为PHP开发人员提供的能够编写可编译/静态类型的高级语言.是优秀的 ...

  4. Inspinia_admin-V2.3原版(英文)

    Inspinia_admin-V2.3原版(英文) Inspinia_admin-V2.3 BootStrap原版(英文) 原版是老外开发的,结果 国内某人翻译成中文版进行二次开发 卖998 演示地址 ...

  5. springboot入门_模板

    springboot中已经不推荐使用jsp,而是推荐使用模板,如freemarker,thymeleaf等,本文记录在sprigboot中使用模板. 创建一个maven的springboot工程, f ...

  6. Redis 设置开机启动

    1. 将下列代码保存为文件redis, 置于 /etc/init.d 下面 ########################### # chkconfig: 2345 90 10 redis服务必须在 ...

  7. 转 Caffe学习系列(3):视觉层(Vision Layers)及参数

    所有的层都具有的参数,如name, type, bottom, top和transform_param请参看我的前一篇文章:Caffe学习系列(2):数据层及参数 本文只讲解视觉层(Vision La ...

  8. 【前端】Vue和Vux开发WebApp日志一、整合vue+cordova和webpack+gulp

    转载请注明出处:http://www.cnblogs.com/shamoyuu/p/vue_vux.html 项目github地址:https://github.com/shamoyuu/vue-vu ...

  9. 一句python,一句R︱模块导入与查看、数据读写出入、数据查看函数、数据类型、遍历文件

    先学了R,最近刚刚上手python,所以想着将python和R结合起来互相对比来更好理解python.最好就是一句python,对应写一句R. pandas中有类似R中的read.table的功能,而 ...

  10. ubuntu 重启命令,ubuntu 重启网卡方法

    ubuntu 重启命令 重启命令:1.reboot2.shutdown -r now 立刻重启(root用户使用)3.shutdown -r 10 过10分钟自动重启(root用户使用)4.shutd ...