7 -- Spring的基本用法 -- 3...
7.3 Spring 的核心机制 : 依赖注入
Spring 框架的核心功能有两个。
Spring容器作为超级大工厂,负责创建、管理所有的Java对象,这些Java对象被称为Bean。
Spring容器管理容器中Bean之间的依赖关系,Spring使用一种被称为“依赖注入”的方式来管理Bean之间的依赖关系。
7.3.1 理解依赖注入
当某个java对象需要调用另一个Java对象的方法时,在传统模式下通常有如下两种做法:
1. 原始做法 : 调用者主动创建被依赖对象,然后在调用被依赖对象的方法。
2. 简单工厂模式 : 调用者先找到被依赖对象的工厂,然后主动通过工厂去获取被依赖对象,最后在调用被依赖对象的方法。
解1:由于调用者需要通过形如“new Person()”的代码创建对象,因此必然导致调用者与被依赖对象实现类的硬编码耦合,非常不利于项目升级的维护。
解2:对于简单工厂的方式,大致需要把握三点:①调用者面向被依赖对象的接口编程;②将被依赖对象的创建交给工厂完成;③调用者通过工厂来获得被依赖组件。调用者只需与被依赖对象的接口耦合,避免了类层次的硬编码耦合。缺点:调用组件需要主动通过工厂去获取被依赖对象,这就会带来调用组件与被依赖对象工厂的耦合。
使用Spring框架的两个主要改变是:
程序无须使用 new 调用构造器去创建对象。所有的Java对象都可交给 Spring 容器去创建。
当调用者需要调用被依赖对象的方法时,调用者无须主动获取被依赖对象,只要等待 Spring 容器注入即可。
依赖注入通常有两种:
设值注入 : IoC 容器使用成员变量的setter方法来注入被依赖对象。
构造注入 : IoC 容器使用构造器来注入被依赖对象。
7.3.2 设值注入
设值注入是指IoC容器通过成员变量的setter方法来注入被依赖对象。
Spring 推荐面向接口编程。不管是调用者,还是被依赖对象,都应该为之定义接口,程序应该面向它们的接口,而不是面向实现类编程,这样以便程序后期的升级、维护。
Spring 推荐面向接口编程,这样可以更好地让规范和实现分离,从而提供更好的解耦。对于一个Java EE应用,不管是DAO组件,还是Service组件,都应该先定义一个接口,该接口定义了该组件应该实现的功能,但功能的实现则由实现类提供。
Interface : Person
package edu.pri.lime._7_3_2.bean; //定义Person对象应遵守的规范
public interface Person { // 定义一个使用斧头的方法
public void useAxe(); }
Interface :Axe
package edu.pri.lime._7_3_2.bean; //定义Axe对象应遵守的规范
public interface Axe { // Axe 接口中定义一个chop()方法
public String chop();
}
Class :Chinese
package edu.pri.lime._7_3_2.bean.impl; import edu.pri.lime._7_3_2.bean.Axe;
import edu.pri.lime._7_3_2.bean.Person; public class Chinese implements Person { private Axe axe;
// 设值注入所需的setter()方法
public void setAxe(Axe axe) {
this.axe = axe;
}
//实现Person接口的userAxe()方法
public void useAxe() {
// 调用axe的 chop()方法
// 表明Person对象依赖于axe对象
System.out.println(axe.chop());
}
}
Class : StoneAxe
package edu.pri.lime._7_3_2.bean.impl;
import edu.pri.lime._7_3_2.bean.Axe;
public class StoneAxe implements Axe {
public String chop() {
// TODO Auto-generated method stub
return "石斧砍柴好慢";
}
}
配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <!-- 配置名为chinese的Bean。其实现类是edu.pri.lime._7_3_2.bean.impl.Chinese类 -->
<bean id="person" class="edu.pri.lime._7_3_2.bean.impl.Chinese">
<!-- 驱动调用chinese的setAxe()方法,将容器中的stoneAxe Bean 作为传入参数 -->
<property name="axe" ref="stoneAxe"/>
</bean> <!-- 配置名为StoneAxe的Bean,其实现类是edu.pri.lime._7_3_2.bean.impl.StoneAxe类 -->
<bean id="stoneAxe" class="edu.pri.lime._7_3_2.bean.impl.StoneAxe"/> </beans>
Class : TestBean
package edu.pri.lime._7_3_2.mian; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.pri.lime._7_3_2.bean.Person;
import edu.pri.lime._7_3_2.bean.impl.Chinese; public class BeanTest { public static void main(String[] args){
// 创建Spring容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_3_2.xml");
// 获取chinese 实例
Person per = ctx.getBean("chinese", Chinese.class);
// 调用 useAxe()方法
per.useAxe();
}
}
Class : SteelAxe
package edu.pri.lime._7_3_2.bean.impl;
import edu.pri.lime._7_3_2.bean.Axe;
public class SteelAxe implements Axe {
public String chop() {
// TODO Auto-generated method stub
return "钢斧砍柴真快";
}
}
Class : TestBean
package edu.pri.lime._7_3_2.main; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.pri.lime._7_3_2.bean.Person;
import edu.pri.lime._7_3_2.bean.impl.Chinese; public class BeanTest { public static void main(String[] args){
//创建Spring容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_3_2.xml");
//获取chinese 实例
Person per = ctx.getBean("chinese", Chinese.class);
//调用 useAxe()方法
per.useAxe(); Person chi = ctx.getBean("china",Chinese.class);
chi.useAxe();
}
}
Spring IoC 容器的三个基本要点:
应用程序的各组件面向接口编程。面向接口编程可以将组件之间的耦合关系提升到接口层次,从而有利于项目后期的扩展。
应用程序的各组件不再由程序主动创建,而是有Spring容器来负责产生并初始化。
Spring 采用配置文件或注解来管理 Bean 的实现类、依赖关系,Spring容器则根据配置文件或注解,利用反射来创建实例,并为之注入依赖关系。
7.3.3 构造注入
在构造实例时,已经为其完成依赖关系的初始化,这种利用构造器来设置依赖关系的方式,被称为构造注入。
驱动Spring 在底层以反射方式执行带指定参数的构造器,当执行带参数的构造器时,就可利用构造器参数对成员变量执行初始化------这就是构造注入的本质。
<bean.../> 元素默认驱动Spring调用无参数的构造器来创建对象。使用<constructor-arg.../>子元素代表一个构造器参数,如果<bean.../>元素包含N个<contructor-arg.../>子元素,就会驱动Spring调用带N个参数的构造器来创建对象。
Class :Chinese
package edu.pri.lime._7_3_3.bean.impl; import edu.pri.lime._7_3_2.bean.Axe;
import edu.pri.lime._7_3_2.bean.Person; public class Chinese implements Person { private Axe axe; public Chinese() {
super();
// TODO Auto-generated constructor stub
} // 未有setter()方法,使用构造方法注入
public Chinese(Axe axe) {
super();
this.axe = axe;
} public void useAxe() {
System.out.println(axe.chop());
} }
配置文件 :
<?xml version="1.0" encoding="UTF-8"?>
<!-- Spring 配置文件的根元素,使用Spring-beans-4.0.xsd语义约束 -->
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd"> <!-- 配置名为chinese的Bean。其实现类是edu.pri.lime._7_3_3.bean.impl.Chinese类 -->
<bean id="chinese" class="edu.pri.lime._7_3_3.bean.impl.Chinese">
<!-- 驱动Spring调用Chinese的带一个参数的构造器来创建对象 -->
<constructor-arg ref="stoneAxe"/>
</bean> <!-- 配置名为StoneAxe的Bean,其实现类是edu.pri.lime._7_3_2.bean.impl.StoneAxe类 -->
<bean id="stoneAxe" class="edu.pri.lime._7_3_2.bean.impl.StoneAxe" /> <bean id="steelAxe" class="edu.pri.lime._7_3_2.bean.impl.SteelAxe"/>
</beans>
Class : BeanTest
package edu.pri.lime._7_3_3.main; import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; import edu.pri.lime._7_3_2.bean.Person;
import edu.pri.lime._7_3_3.bean.impl.Chinese; public class BeanTest { public static void main(String[] args){
ApplicationContext ctx = new ClassPathXmlApplicationContext("app_7_3_3.xml");
Person per = ctx.getBean("chinese",Chinese.class);
per.useAxe();
}
}
Spring底层,反射机制
String idStr = ... // Spring 解析<bean.../> 元素得到id属性值为chinese
String refStr = ... // Spring 解析 <constructor-arg.../> 元素得到ref属性值为steelAxe
Object paramBean = container.get(refStr);
// Spring 会用反射方式执行下面代码(仅仅示例,为用反射)
Object obj = new Chinese(paramBean);
// container 代表Spring 容器
container.put(idStr,obj);
package edu.pri.lime._7_3_3.main; import java.lang.reflect.Constructor; import edu.pri.lime._7_3_2.bean.Axe;
import edu.pri.lime._7_3_2.bean.Person; public class ReflectTest { public static void main(String[] args) throws Exception{
Class<?> clazzChi = Class.forName("edu.pri.lime._7_3_3.bean.impl.Chinese");
Class<?> clazzAxe = Class.forName("edu.pri.lime._7_3_2.bean.impl.SteelAxe");
Class<?> clazz = Class.forName("edu.pri.lime._7_3_2.bean.Axe");
Axe axe = (Axe) clazzAxe.newInstance();
Constructor<?> con = clazzChi.getConstructor(clazz);
Person per = (Person) con.newInstance(axe);
per.useAxe();
}
}
配置<constructor-arg .../> 元素是可指定一个index属性,用于指定该构造参数值将作为第几个构造参数数值:index=0表明该构造参数值将作为第一个构造参数值。
<constructor-arg value="23" type="int"/>:用于更明确的指定数据类型。
7.3.4 两种注入方式的对比
7 -- Spring的基本用法 -- 3...的更多相关文章
- SpringMVC +mybatis+spring 结合easyui用法及常见问题总结
SpringMVC +mybatis+spring 结合easyui用法及常见问题总结 1.FormatString的用法. 2.用postAjaxFillGrid实现dataGrid 把form表单 ...
- Spring中@Async用法详解及简单实例
Spring中@Async用法 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类 ...
- (转)Spring中@Async用法总结
原文:http://blog.csdn.net/blueheart20/article/details/44648667 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的: ...
- Spring中@Async用法总结
引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在Spring 3. ...
- spring AOP的用法
AOP,面向切面编程,它能把与核心业务逻辑无关的散落在各处并且重复的代码给封装起来,降低了模块之间的耦合度,便于维护.具体的应用场景有:日志,权限和事务管理这些方面.可以通过一张图来理解下: Spri ...
- Spring常用注解用法总结
转自http://www.cnblogs.com/leskang/p/5445698.html 1.@Controller 在SpringMVC 中,控制器Controller 负责处理由Dispat ...
- Spring中@Value用法收集
一.配置方式 @Value需要参数,这里参数可以是两种形式: @Value("#{configProperties['t1.msgname']}") 或者 @Value(" ...
- Spring data redis-StringRedisTemplate 用法
Spring-data-redis为spring-data模块中对redis的支持部分,简称为“SDR”,提供了基于jedis客户端API的高度封装以及与spring容器的整合,事实上jedis客户端 ...
- Spring.Net简单用法
Spring.Net其实就是抽象工厂,只不过更加灵活强大,性能上并没有明显的区别. 它帮我们实现了控制反转. 其有两种依赖注入方式. 第一:属性注入 第二:构造函数注入 首先,我们去 Spring. ...
- 7 -- Spring的基本用法 -- 6...
7.6 Spring 3.0 提供的Java配置管理 Spring 允许使用Java类进行配置管理,可以不使用XML来管理Bean,以及Bean之间的依赖关系. Interface :Person p ...
随机推荐
- Meteor全栈开发平台 - 不仅仅是前端
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,博客地址为http://www.cnblogs.com/jasonnode/ .网站上有对应每一 ...
- CEGUI环境配置
由于最近项目需要CEGUI做界面,于是我去下载了CEGUI源码,但是却不知道怎么搭建.网上的教程都不是很详细,不能让我们这种新手理解,经过几天折腾,终于弄好了,特此记录下来. 1.下载官网CEGUI源 ...
- [转] 经典SQL练习题
原题目来自qaz13177_58_CSDN博客 http://blog.csdn.net/qaz13177_58_/article/details/5575711/#sql 只是更新个人答案供参考 表 ...
- OA工作流规格--转
工作流是整个OA系统的核心,也是BPM的核心,工作流到 底需要实现哪些功能,本文就此以用户的需求为蓝本进行阐述.工作流表面看起来是很简单的,无非是一个表单模板,一个流程定义,然后起草后根据设定的流程一 ...
- 进制转换及API接口中的转换
//十进制转二进制Console.WriteLine("十进制166的二进制表示: "+Convert.ToString(166, 2));//十进制转八进制Console.Wri ...
- [已解决] 快速理解RSA算法
RSA算法基础详解 http://www.cnblogs.com/hykun/p/RSA.html RSA算法原理(一) http://www.ruanyifeng.com/blog/2013/06/ ...
- scoi2010&&bzoj1858序列操作
[题目描述] lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a ...
- Unity2D 里的场景缩放实现
闲时以 Unity2D 练手时想实现端游里的场景缩放功能,而网上的代码几乎全是 3D 场景缩放相关,所以我自己编写了个 2D 场景缩放脚本(C#). 代码如下: using UnityEngine; ...
- 类加载机制(深入理解JAVA虚拟机学习笔记)
1.类加载机制的定义 将class文件加载到内存,然后对class文件中的数据进行校验.解析和初始化,转换成可以被虚拟机直接使用的JAVA类型,这就是虚拟机的类加载机制.(在JAVA中,类的加载.连接 ...
- Socket之TCP连接_TcpNoDelay
摘自: http://jerrypeng.me/2013/08/mythical-40ms-delay-and-tcp-nodelay/