Spring【依赖注入】就是这么简单
前言
在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方法给属性注入值
- 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【依赖注入】就是这么简单的更多相关文章
- Spring依赖注入 --- 简单使用说明
		Spring依赖注入 --- 简单使用说明 本文将对spring依赖注入的使用做简单的说明,enjoy your time! 1.使用Spring提供的依赖注入 对spring依赖注入的实现方法感兴趣 ... 
- Spring依赖注入:注解注入总结
		更多11 spring 依赖注入 注解 java 注解注入顾名思义就是通过注解来实现注入,Spring和注入相关的常见注解有Autowired.Resource.Qualifier.S ... 
- Spring 依赖注入,在Main方法中取得Spring控制的实例
		Spring依赖注入机制,在Main方法中通过读取配置文件,获取Spring注入的bean实例.这种应用在实训的时候,老师曾经说过这种方法,而且学Spring入门的时候都会先学会使用如何在普通的jav ... 
- Spring依赖注入的三种方式
		看过几篇关于Spring依赖注入的文章,自己简单总结了一下,大概有三种方式: 1.自动装配 通过配置applicationContext.xml中的标签的default-autowire属性,或者标签 ... 
- 二十7天 春雨滋润着无形 —Spring依赖注入
		6月11日,明确."夏条绿已密,朱萼缀明鲜.炎炎日正午,灼灼火俱燃." IT人习惯把详细的事物加工成的形状一致的类.正是这种一致,加上合适的规范.才干彰显对象筋道的牙感和bean清 ... 
- SSH深度历险记(八) 剖析SSH核心原则+Spring依赖注入的三种方式
		于java发育.一类程序猿必须依靠类的其他方法,它是通常new依赖类的方法,然后调用类的实例,这样的发展问题new良好的班统一管理的例子.spring提出了依赖注入的思想,即依赖类不由程 ... 
- SSH深度历险(八) 剖析SSH核心原理+Spring依赖注入的三种方式
		在java开发中,程序员在某个类中需要依赖其它类的方法,则通常是new一个依赖类再调用类实例的方法,这种开发存在的问题是new的类实例不好统一管理,spring提出了依赖注入的思想,即依 ... 
- Spring依赖注入原理分析
		在分析原理之前我们先回顾下依赖注入的概念: 我们常提起的依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念.具体含义是:当某个角色( ... 
- Spring依赖注入servlet会话监听器
		Spring提供了一个 “ContextLoaderListener” 监听器,以使 Spring 依赖注入到会话监听器. 在本教程中,通过添加一个 Spring 依赖注入一个bean 到会话监听器修 ... 
- Spring学习笔记——Spring依赖注入原理分析
		我们知道Spring的依赖注入有四种方式,各自是get/set方法注入.构造器注入.静态工厂方法注入.实例工厂方法注入 以下我们先分析下这几种注入方式 1.get/set方法注入 public cla ... 
随机推荐
- mac下更新自带的PHP版本到5.6
			OS X 10.11自带的PHP版本是PHP 5.5.x,如果我们想更新PHP的版本到5.6或者是7.0该怎么办呢? 下载和安装PHP 5.6 打开终端并且运行如下命令: curl -s http:/ ... 
- word在页眉中插入页码
			编辑页眉时,插入-页码-当前位置-普通数字 
- Python比较运算符
			判断两个对象之间的关系,和条件选择和循环结合使用的 以下假设变量a为10,变量b为20: 示例1:输入三个互不相等的整数,按照从小到大输出 num01,num02,num03 = eval(input ... 
- Yii2中后台用前台的代码设置验证码显示不出来?
			我说的是直接修改advanced模板.细心人会发现模板里在contact里有,登录也想要就仿照contact中的做法.前台好了,后台登录也要验证码,就把前台代码拿过来,可惜前后台的SiteContro ... 
- 硬件能力与智能AI-Zoomla!逐浪CMS2 x3.9.2正式发布
			北京时间2017年9月10日,领先的CMS网站内容管理系统与生产力软件研发厂商-Zoomla!逐浪CMS团队发布其年度重要产品:Zoomla!逐浪CMS2 x3.9.2,引领国内门户.移动.微商以及生 ... 
- JPA实体的常用注解
			@Entity 标注于实体类上,通常和@Table是结合使用的,代表是该类是实体类@Table 标注于实体类上,表示该类映射到数据库中的表,没有指定名称的话就表示与数据库中表名为该类的简单类名的表名相 ... 
- 《python机器学习—预测分析核心算法》笔记1
			参见原书 1.1-1.4节 一.惩罚线性回归模型 基本特性: 1.训练时间快,使用训练好的模型进行预测的时间也快2.应用于高速交易.互联网广告的植入等3.解决回归.分类问题 最重要的特性:能明确指出, ... 
- jmeter 脚本规范
			总结了一下公司正在用 jmeter 脚本规范. 使用 jmeter 进行接口级测试, 随着接口增多以及业务逻辑越来越复杂, 导致 jmeter 脚本的维护会更加困难.针对实际使用中发现的问题进行一些规 ... 
- linux权限归属及特殊权限设置
			访问权限:读取:允许查看内容 -read写入:允许修改内容 -write可执行:允许运行和切换 -excute(以上三点rwx共同决定最终权限)归属关系:所有者:拥有此文件/目录的用户 -user所属 ... 
- Linux基础四
			vim编辑器 vi编辑器的增强版,语法高亮等扩展功能 vim三种工作模式 a,i,o等键输出模式 命令模式,输入模式,末行模式 模式间的切换 a:当前行插入 i:当前行插入 o:全新一行插入 :键末 ... 
