二十7天 春雨滋润着无形 —Spring依赖注入
6月11日,明确。“夏条绿已密,朱萼缀明鲜。炎炎日正午,灼灼火俱燃。”
IT人习惯把详细的事物加工成的形状一致的类。正是这种一致,加上合适的规范。才干彰显对象筋道的牙感和bean清香的味道。
Spring比谁都清楚OO的奥妙,让组件之间的依赖关系由容器在执行时期决定,称作依赖注入(Dependency Injection)。
以下用一通俗的样例,一探依赖注入奥妙。
设计模式中的一个原则:针对接口编程。不要针对实现编程。
一、设计两个接口:
(1)奶制品接口—MilkProductInterface.java
package edu.eurasia.IOC; public interface MilkProductInterface {
public void drinkMilk();
public void eatCheese();
}
(2)奶制品接口的实现类—Milk.java
package edu.eurasia.IOC; public class Milk implements MilkProductInterface { public void drinkMilk() {
System.out.println("新奇的牛奶真好喝! ");
} public void eatCheese() {
System.out.println("仅仅有鲜奶,无奶酪o(╯□╰)o");
}
}
(3)奶制品接口的实现类—Cheese.java
package edu.eurasia.IOC; public class Cheese implements MilkProductInterface { public void drinkMilk() {
System.out.println("仅仅有奶酪。无鲜奶o(╯□╰)o"); } public void eatCheese() {
System.out.println("发酵后的美味奶酪真好吃! "); }
}
(4)人的接口—PersonInterface.java
package edu.eurasia.IOC; public interface PersonInterface {
public void drink();
public void eat();
}
(5)人接口的实现类—Person.java
正常情况下,人要喝牛奶。吃奶酪。这样写就ok了。
package edu.eurasia.IOC; public class Person implements PersonInterface {
public void drink() {
MilkProductInterface milk = new Milk();
milk.drinkMilk();
} public void eat() {
MilkProductInterface cheese = new Cheese();
cheese.eatCheese();
}
}
(6)測试类—TestIOC.java
package edu.eurasia.IOC; import org.junit.Test; public class TestIOC {
@Test
public void eatdrink(){
PersonInterface p = new Person();
p.drink();
p.eat();
}
}
结果输出:新奇的牛奶真好喝!
发酵后的美味奶酪真好吃。
上述代码。非常多刚開始学习的人看不出来有什么问题。可是。类是一样的类。一“new”见高下。使用“new”的时候,就已经在实例化一个详细类了,这就是一种实现,仅仅要有详细类的出现。就会导致代码更缺乏弹性。
重温设计模式中的一个原则:针对接口编程。不要针对实现编程。
简单的说依赖注入的思想常见的一种情况:假设一个类中要复用另外一个类中的功能时,可能会首先想到继承,假设知道Ioc这样的思想的话,就不会用继承,会立即想到把要用到功能抽取出来,在我们要用到的类中仅仅需通过set方法简单的注入就能够了,事实上这里用到了对象的组合取代继承。这样不仅避免了单一继承,还非常好的实现了松耦合。同一时候也遵循了面向对象的编程的设计原则:多用组合,少用继承。
二、依赖注入(Set):
(1)改动人接口的实现类—Person.java
package edu.eurasia.IOC; public class Person implements PersonInterface {
private MilkProductInterface milkX; public void setMilkX(MilkProductInterface milkX) {
this.milkX = milkX;
} @Override
public void drink() {
milkX.drinkMilk();
} @Override
public void eat() {
milkX.eatCheese(); }
}
声明一个MilkProductInterface接口变量milkX,这个milkX代表随意一种详细的奶制品,可能是牛奶milk,也可能是奶酪cheese,还有可能是奶茶milky
tea...。总之,我们能够动态的在执行时改变它的详细属性。怎么改?别着急,你发现了milkX的set方法。
哈哈,这就是大名鼎鼎的Set注入(setter
injection)。
看到了注入,那么依赖(Dependency)在哪里?
我们对着雾霾喊: 依赖。我们的好DI。 你在哪里呵,你在哪里? 你可知道,我们想念你...
雾霾翻滚: 它就在配置文件中...
(2)编写配置文件—applicationContext.xml,放在src以下。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="milk" class="edu.eurasia.IOC.Milk"></bean>
<bean id="cheese" class="edu.eurasia.IOC.Cheese"></bean> <bean id="person" class="edu.eurasia.IOC.Person">
<property name="milkX" ref="milk"></property>
</bean>
</beans>
配置文件是Spring依赖注入的关键:
首先,定义两个bean,第一个bean的id是milk, class指定该bean实例的实现类;第二个bean的id是cheese。class相同指定该bean实例的实现类。这两个bean是为以下的Bean提供引用注入的。
其次,再定义一个bean,bean的id是person,
class指定该bean实例的实现类。property元素用来指定须要容器注入的属性,属性名milkX要与Person.java中的属性一致。ref引用要注入的值即上面定义的任一个id。不同的id。就是注入的不同值,因此Person类必须拥有setMilkX方法。说了半天,灵活性就在这里体现了。
从配置文件中,能够看到Spring管理bean的机灵性。bean与bean之间的依赖关系放在配置文件中组织,而不是写在代码里。
通过配置文件的
指定,Spring能精确地为每一个bean注入属性。因此,配置文件中的bean的class元素,不能不过接口。而必须是真正的实现类。
Spring会自己主动接管每一个bean定义里的property元素定义。Spring会在运行无參数的构造器后、创建默认的bean实例后,调用相应的setter方法为注入属性值。
property定义的属性值将不再由该bean来主动创建、管理,而改为被动接收Spring的注入。
每一个bean的id属性是该bean的惟一标识,程序通过id属性訪问bean。bean与bean的依赖关系也通过id属性完毕。
注:
1、spring配置文件里Bean中的id和name的差别
id:鼓舞使用ID属性来标识一个Bean, 不能重名,能够被DTD验证。不能以数字,符号打头,不能有空格;
name: 能够重名, 后面的覆盖前面。
2、JavaBean关于属性命名的特殊规范
Spring配置文件里<property>元素所指定的属性名和Bean实现类的Setter方法满足Sun JavaBean的属性命名规范:xxx的属性相应setXxx()方法。
普通情况下。Java的属性变量名都以小写字母开头,如maxSpeed、brand等。但也存在特殊的情况,考虑到一些特殊意义的大写英文缩略词(如USA、XML等),JavaBean也同意大写字母开头的属性变量名,但必须满足“变量的前两个字母要么所有大写,要么所有小写”的要求,如brand、ICCard是合法的,而iC、iCCard是非法的。
(3)改写測试类—TestIOC.java
package edu.eurasia.IOC; import org.junit.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestIOC {
@Test
public void eatdrink(){
AbstractApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Person p = (Person) context.getBean("person");
p.drink();
p.eat();
}
}
程序实例化Spring的上下文,通过Person bean的id来获取bean实例。从而实现面向接口编程。
结果输出:新奇的牛奶真好喝!
仅仅有鲜奶,无奶酪o(╯□╰)o
更改applicationContext.xml里面的ref="cheese"。
此时再次运行程序。将得到例如以下结果:
仅仅有奶酪。无鲜奶o(╯□╰)o
发酵后的美味奶酪真好吃!
採用setter方法为目标bean注入属性的方式,称为设值注入。
此外。另一种叫构造注入。所谓构造注入。指通过构造函数来完毕依赖关系的设定,而不是通过setter方法。
三、依赖注入(构造):
(1)改动人接口的实现类—Person.java
package edu.eurasia.IOC; public class Person implements PersonInterface { private MilkProductInterface milkX; public Person(MilkProductInterface milkX) {
super();
this.milkX = milkX;
} @Override
public void drink() { milkX.drinkMilk();
} @Override
public void eat() {
milkX.eatCheese(); }
}
(2)改动配置文件—applicationContext.xml
<? xml version="1.0" encoding="UTF-8"? >
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <bean id="milk" class="edu.eurasia.IOC.Milk"></bean>
<bean id="cheese" class="edu.eurasia.IOC.Cheese"></bean> <bean id="person" class="edu.eurasia.IOC.Person">
<!-- <property name="milkX" ref="milk"></property> -->
<constructor-arg ref="milk"></constructor-arg>
</bean>
</beans>
运行效果与使用设值注入时的运行效果全然一样。差别在于:创建Person实例中属性的时机不同—设值注入是现创建一个默认的bean实例,然后调用相应的构造方法注入依赖关系。
而构造注入则在创建bean实例时,已经完毕了依赖关系。
二十7天 春雨滋润着无形 —Spring依赖注入的更多相关文章
- 二十、MVC的WEB框架(Spring MVC)
一.Spring MVC 运行原理:客户端请求提交到DispatcherServlet,由DispatcherServlet控制器查询HandlerMapping,找到并分发到指定的Controlle ...
- Spring 依赖注入(二、注入参数)
注入参数基本分7类: 1.基本类型值 2.注入bean 3.内部bean 4.注入null值 5.级联属性 6.List,Set,Map集合的注入 7.properties文件的注入(和集合注入基本是 ...
- 【10分钟学Spring】:(二)一文搞懂spring依赖注入(DI)
Spring最基础的特性就是创建bean.管理bean之间的依赖关系.下面通过具体实例演示该如何装配我们应用中的bean. Spring提供了三种主要的装配机制 在xml中进行显示的配置 在Java中 ...
- SpringBoot进阶教程(二十六)整合Redis之共享Session
集群现在越来越常见,当我们项目搭建了集群,就会产生session共享问题.因为session是保存在服务器上面的.那么解决这一问题,大致有三个方案,1.通过nginx的负载均衡其中一种ip绑定来实现( ...
- WCF学习之旅—第三个示例之三(二十九)
上接WCF学习之旅—第三个示例之一(二十七) WCF学习之旅—第三个示例之二(二十八) 在上一篇文章中我们创建了实体对象与接口协定,在这一篇文章中我们来学习如何创建WCF的服务端代码.具体步骤见下面. ...
- WCF学习之旅—TcpTrace工具(二十六)
止文(WCF学习之旅—TcpTrace工具(二十五))介绍了关于TcpTrance的一种使用方式,接下来介绍第二种使用方式. 三.通过ListenUri实现基于tcpTracer的消息路由 对于路由的 ...
- WCF学习之旅—实现支持REST客户端应用(二十四)
WCF学习之旅—实现REST服务(二十二) WCF学习之旅—实现支持REST服务端应用(二十三) 在上二篇文章中简单介绍了一下RestFul与WCF支持RestFul所提供的方法,及创建一个支持RES ...
- geotrellis使用(二十五)将Geotrellis移植到spark2.0
目录 前言 升级spark到2.0 将geotrellis最新版部署到spark2.0(CDH) 总结 一.前言 事情总是变化这么快,前面刚写了一篇博客介绍如何将geotrellis移植 ...
- geotrellis使用(二十二)实时获取点状目标对应的栅格数据值
目录 前言 实现方法 总结 一.前言 其实这个功能之前已经实现,今天将其采用1.0版的方式进行了重构与完善,现将该内容进行总结. 其实这个功能很常见,比如google地球上 ...
随机推荐
- UVa 11371 - Number Theory for Newbies
題目:給你一個數字n.將裡面每位的數又一次組合形成a,b.使得a-b最大且是9的倍數. 分析:數論. 題目要求a,b和n的位數同样,不能有前導0. 定理1:交換一個數字中的某兩個位的數,形成的新數組和 ...
- 深度学习系列之CNN核心内容
导读 怎么样来理解近期异常火热的深度学习网络?深度学习有什么亮点呢?答案事实上非常简答.今年十月份有幸參加了深圳高交会的中科院院士论坛.IEEE fellow汤晓欧做了一场精彩的报告,这个问题被汤大神 ...
- Android中使用SurfaceView和Canvas来绘制动画
事实上每一个View中都有Canvas能够用来绘制动画.仅仅须要在这个View中重载onDraw()方法就能够,可是SurfaceView类是一个专门用来制动动画的类. Canvas(中文叫做&quo ...
- HBase总结(二十)HBase经常使用shell命令具体说明
进入hbase shell console $HBASE_HOME/bin/hbase shell 假设有kerberos认证,须要事先使用对应的keytab进行一下认证(使用kinit命令),认证成 ...
- fusionchart实现ZoomLine 源码 破解版 能够导出
近期画油量曲线须要用到ZoomLine官网看了好几天.如今整理出来供大家參考使用 zoomline.html源码 <!DOCTYPE HTML PUBLIC "-//W3C//DTD ...
- ImportError: No module named _sqlite3 - 代码分享
ImportError: No module named _sqlite3 - 代码分享 ImportError: No module named _sqlite3 作者:86市场网 点击 ...
- nyist oj 311 全然背包 (动态规划经典题)
全然背包 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描写叙述 直接说题意,全然背包定义有N种物品和一个容量为V的背包.每种物品都有无限件可用.第i种物品的体积是c,价值是 ...
- hdu4487(概率dp)
题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4487 题意:开始位置在0,每一步可以向右向左或者不动,问走了n步后,路径中能到达最右的期望. 分析:d ...
- Codeforces Round #269 (Div. 2) A B C
先说C 题目链接:http://codeforces.com/problemset/problem/471/C 题目意思:有 n 张卡,问能做成多少种不同楼层(floor)的 house.注意这 n ...
- 【Java】运用JDBC实现一个注册、登录系统的编写
数据库的建立 首先,建立一个数据库,存储注册成功的账户信息. 其SQL的DDL语句如下: CREATE TABLE `jdbctest` ( `id` int(10) NOT NULL auto_in ...