设计 微网站铭万做的网站
设计 微网站,铭万做的网站,河南手机网站建设,建设教育工程网站Spring是为了解决企业应用开发的复杂性而创建的一个轻量级的控制反转#xff08;IoC#xff09;和面向切面#xff08;AOP#xff09;的容器框架。在这句话中重点有两个#xff0c;一个是IoC#xff0c;另一个是AOP。今天我们讲第一个IoC。 一. IoC理论的背景 我们都知道… Spring是为了解决企业应用开发的复杂性而创建的一个轻量级的控制反转IoC和面向切面AOP的容器框架。在这句话中重点有两个一个是IoC另一个是AOP。今天我们讲第一个IoC。 一. IoC理论的背景 我们都知道在采用面向对象方法设计的软件系统中它的底层实现都是由N个对象组成的所有的对象通过彼此的合作最终实现系统的业务逻辑。 如果我们打开机械式手表的后盖就会看到与上面类似的情形各个齿轮分别带动时针、分针和秒针顺时针旋转从而在表盘上产生正确的时间。图1中描述的就是 这样的一个齿轮组它拥有多个独立的齿轮这些齿轮相互啮合在一起协同工作共同完成某项任务。我们可以看到在这样的齿轮组中如果有一个齿轮出了问 题就可能会影响到整个齿轮组的正常运转。齿轮组中齿轮之间的啮合关系,与软件系统中对象之间的耦合关系非常相似。对象之间的耦合关系是无法避免的也是必要的这是协同工作的基础。现在伴随着工业级应用的规模越来越庞大对象之间的依赖关系也越来越复杂经常会出现对象之间的多重依赖性关系因此架构师和设计师对于系统的分析和设计将面临 更大的挑战。对象之间耦合度过高的系统必然会出现牵一发而动全身的情形。 耦合关系不仅会出现在对象与对象之间也会出现在软件系统的各模块之间以及软件系统和硬件系统之间。如何降低系统之间、模块之间和对象之间的耦合度是软件工程永远追求的目标之一。为了解决对象之间的耦合度过高的问题软件专家Michael Mattson提出了IOC理论用来实现对象之间的“解耦”目前这个理论已经被成功地应用到实践当中很多的J2EE项目均采用了IOC框架产品Spring。 2. 什么是控制反转(IoC) IOC是Inversion of Control的缩写多数书籍翻译成“控制反转”还有些书籍翻译成为“控制反向”或者“控制倒置”。1996年Michael Mattson在一篇有关探讨面向对象框架的文章中首先提出了IOC 这个概念。对于面向对象设计及编程的基本思想前面我们已经讲了很多了不再赘述简单来说就是把复杂系统分解成相互合作的对象这些对象类通过封装以后内部实现对外部是透明的从而降低了解决问题的复杂度而且可以灵活地被重用和扩展。IOC理论提出的观点大体是这样的借助于“第三方”实现具有依 赖关系的对象之间的解耦如下图 大家看到了吧由于引进了中间位置的“第三方”也就是IOC容器使得A、B、C、D这4个对象没有了耦合关系齿轮之间的传动全部依靠“第三方”了 全部对象的控制权全部上缴给“第三方”IOC容器所以IOC容器成了整个系统的关键核心它起到了一种类似“粘合剂”的作用把系统中的所有对象粘合 在一起发挥作用如果没有这个“粘合剂”对象与对象之间会彼此失去联系这就是有人把IOC容器比喻成“粘合剂”的由来。 我们再来做个试验把上图中间的IOC容器拿掉然后再来看看这套系统 我们现在看到的画面就是我们要实现整个系统所需要完成的全部内容。这时候A、B、C、D这4个对象之间已经没有了耦合关系彼此毫无联系这样的话 当你在实现A的时候根本无须再去考虑B、C和D了对象之间的依赖关系已经降低到了最低程度。所以如果真能实现IOC容器对于系统开发而言这将是 一件多么美好的事情参与开发的每一成员只要实现自己的类就可以了跟别人没有任何关系 我们再来看看控制反转(IOC)到底为什么要起这么个名字我们来对比一下 软件系统在没有引入IOC容器之前如图1所示对象A依赖于对象B那么对象A在初始化或者运行到某一点的时候自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B控制权都在自己手上。 软件系统在引入IOC容器之后这种情形就完全改变了如图3所示由于IOC容器的加入对象A与对象B之间失去了直接联系所以当对象A运行到需要对象B的时候IOC容器会主动创建一个对象B注入到对象A需要的地方。 通过前后的对比我们不难看出来对象A获得依赖对象B的过程,由主动行为变为了被动行为控制权颠倒过来了这就是“控制反转”这个名称的由来。 3. IOC的别名依赖注入(DI) 2004年Martin Fowler探讨了同一个问题既然IOC是控制反转那么到底是“哪些方面的控制被反转了呢”经过详细地分析和论证后他得出了答案“获得依赖对象的过程被反转了”。控制被反转之后获得依赖对象的过程由自身管理变为了由IOC容器主动注入。于是他给“控制反转”取了一个更合适的名字叫做“依赖 注入Dependency Injection”。他的这个答案实际上给出了实现IOC的方法注入。所谓依赖注入就是由IOC容器在运行期间动态地将某种依赖关系注入到对象之中。 所以依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情就是指通过引入IOC容器利用依赖关系注入的方式实现对象之间的解耦。 我们举一个生活中的例子来帮助理解依赖注入的过程。大家对USB接口和USB设备应该都很熟悉吧USB为我们使用电脑提供了很大的方便现在有很多的外部设备都支持USB接口。 现在我们利用电脑主机和USB接口来实现一个任务从外部USB设备读取一个文件。 电脑主机读取文件的时候它一点也不会关心USB接口上连接的是什么外部设备而且它确实也无须知道。它的任务就是读取USB接口挂接的外部设备只要符 合USB接口标准即可。所以如果我给电脑主机连接上一个U盘那么主机就从U盘上读取文件如果我给电脑主机连接上一个外置硬盘那么电脑主机就从外置 硬盘上读取文件。挂接外部设备的权力由我作主即控制权归我至于USB接口挂接的是什么设备电脑主机是决定不了它只能被动的接受。电脑主机需要外部 设备的时候根本不用它告诉我我就会主动帮它挂上它想要的外部设备你看我的服务是多么的到位。这就是我们生活中常见的一个依赖注入的例子。在这个过程 中我就起到了IOC容器的作用。 通过这个例子,依赖注入的思路已经非常清楚当电脑主机读取文件的时候我就把它所要依赖的外部设备帮他挂接上。整个外部设备注入的过程和一个被依赖的对象在系统运行时被注入另外一个对象内部的过程完全一样。 我们把依赖注入应用到软件系统中再来描述一下这个过程 对象A依赖于对象B,当对象 A需要用到对象B的时候IOC容器就会立即创建一个对象B送给对象A。IOC容器就是一个对象制造工厂你需要什么它会给你送去你直接使用就行了 而再也不用去关心你所用的东西是如何制成的也不用关心最后是怎么被销毁的这一切全部由IOC容器包办。 在传统的实现中由程序内部代码来控制组件之间的关系。我们经常使用new关键字来实现两个组件之间关系的组合这种实现方式会造成组件之间耦合。IOC 很好地解决了该问题它将实现组件间关系从程序内部提到外部容器也就是说由容器在运行期将组件间的某种依赖关系动态注入组件中。 4. IOC为我们带来了什么好处 我们还是从USB的例子说起使用USB外部设备比使用内置硬盘到底带来什么好处 第一、USB设备作为电脑主机的外部设备在插入主机之前与电脑主机没有任何的关系只有被我们连接在一起之后两者才发生联系具有相关性。所以无 论两者中的任何一方出现什么的问题都不会影响另一方的运行。这种特性体现在软件工程中就是可维护性比较好非常便于进行单元测试便于调试程序和诊断 故障。代码中的每一个Class都可以单独测试彼此之间互不影响只要保证自身的功能无误即可这就是组件之间低耦合或者无耦合带来的好处。 第二、USB设备和电脑主机的之间无关性还带来了另外一个好处生产USB设备的厂商和生产电脑主机的厂商完全可以是互不相干的人各干各事他们之间 唯一需要遵守的就是USB接口标准。这种特性体现在软件开发过程中好处可是太大了。每个开发团队的成员都只需要关心实现自身的业务逻辑完全不用去关心 其它的人工作进展因为你的任务跟别人没有任何关系你的任务可以单独测试你的任务也不用依赖于别人的组件再也不用扯不清责任了。所以在一个大中型 项目中团队成员分工明确、责任明晰很容易将一个大的任务划分为细小的任务开发效率和产品质量必将得到大幅度的提高。 第三、同一个USB外部设备可以插接到任何支持USB的设备可以插接到电脑主机也可以插接到DV机USB外部设备可以被反复利用。在软件工程中这 种特性就是可复用性好我们可以把具有普遍性的常用组件独立出来反复利用到项目中的其它部分或者是其它项目当然这也是面向对象的基本特征。显 然IOC不仅更好地贯彻了这个原则提高了模块的可复用性。符合接口标准的实现都可以插接到支持此标准的模块中。 第四、同USB外部设备一样模块具有热插拔特性。IOC生成对象的方式转为外置方式也就是把对象生成放在配置文件里进行定义这样当我们更换一个实现子类将会变得很简单只要修改配置文件就可以了完全具有热插拨的特性。 以上几点好处难道还不足以打动我们让我们在项目开发过程中使用IOC框架吗 5. IOC容器的技术剖析 IOC中最基本的技术就是“反射(Reflection)”编程目前.Net C#、Java和PHP5等语言均支持其中PHP5的技术书籍中有时候也被翻译成“映射”。有关反射的概念和用法大家应该都很清楚通俗来讲就是根据给出的类名字符串方式来动态地生成对象。这种编程方式可以让对象在生成时才决定到底是哪一种对象。反射的应用是很广泛的很多的成熟的框架比如象Java中的Hibernate、Spring框架.Net中 NHibernate、Spring.Net框架都是把“反射”做为最基本的技术手段。 反射技术其实很早就出现了但一直被忽略没有被进一步的利用。当时的反射编程方式相对于正常的对象生成方式要慢至少得10倍。现在的反射技术经过改良优化已经非常成熟反射方式生成对象和通常对象生成方式速度已经相差不大了大约为1-2倍的差距。 我们可以把IOC容器的工作模式看做是工厂模式的升华可以把IOC容器看 作是一个工厂这个工厂里要生产的对象都在配置文件中给出定义然后利用编程语言的的反射编程根据配置文件中给出的类名生成相应的对象。从实现来 看IOC是把以前在工厂方法里写死的对象生成代码改变为由配置文件来定义也就是把工厂和对象生成这两者独立分隔开来目的就是提高灵活性和可维护 性。 6. IOC容器的一些产品 Sun ONE技术体系下的IOC容器有轻量级的有Spring、Guice、Pico Container、Avalon、HiveMind重量级的有EJB不轻不重的有JBossJdon等等。Spring框架作为Java开发中 SSH(Struts、Spring、Hibernate)三剑客之一大中小项目中都有使用非常成熟应用广泛EJB在关键性的工业级项目中也被使 用比如某些电信业务。 .Net技术体系下的IOC容器有Spring.Net、Castle等等。Spring.Net是从Java的Spring移植过来的IOC容 器Castle的IOC容器就是Windsor部分。它们均是轻量级的框架比较成熟其中Spring.Net已经被逐渐应用于各种项目中。 7. 使用IOC框架应该注意什么 使用IOC框架产品能够给我们的开发过程带来很大的好处但是也要充分认识引入IOC框架的缺点做到心中有数杜绝滥用框架。 第一、软件系统中由于引入了第三方IOC容器生成对象的步骤变得有些复杂本来是两者之间的事情又凭空多出一道手续所以我们在刚开始使用IOC框 架的时候会感觉系统变得不太直观。所以引入了一个全新的框架就会增加团队成员学习和认识的培训成本并且在以后的运行维护中还得让新加入者具备同 样的知识体系。 第二、由于IOC容器生成对象是通过反射方式在运行效率上有一定的损耗。如果你要追求运行效率的话就必须对此进行权衡。 第三、具体到IOC框架产品(比如Spring)来讲需要进行大量的配制工作比较繁琐对于一些小的项目而言客观上也可能加大一些工作成本。 第四、IOC框架产品本身的成熟度需要进行评估如果引入一个不成熟的IOC框架产品那么会影响到整个项目所以这也是一个隐性的风险。 我们大体可以得出这样的结论一些工作量不大的项目或者产品不太适合使用IOC框架产品。另外如果团队成员的知识能力欠缺对于IOC框架产品缺乏深 入的理解也不要贸然引入。最后特别强调运行效率的项目或者产品也不太适合引入IOC框架产品象WEB2.0网站就是这种情况。 IoC概念回顾 控制反转Inversion of Control是一个重要的面向对象编程的法则来削减计算机程序的耦合问题。 它还有一个名字叫做依赖注入Dependency Injection。IoC不是什么技术它是一种设计模式。 实例演示 为了更好的说明IoC我为大家举一个简单的例子如有这样一个描述某公司新成立了一个项目组项目组有若干成员和一个项目组长项目组成立后第一次开会上作为项目组长的小李按照惯例首先做了简短的自我介绍。 根据上述的描述如果我们写出如下代码和类图 public class Li { public void introduce() {System.out.println(大家好我是小李);}}public class Team {public void firstMeeting() {Li li new Li();li.introduce();}} 具体类图如下 上述的代码应该说基本完成了相关的需求但是仔细考虑之后就会发现上述的代码是根据具体的场景描述进行的并没有进行抽象这样就导致我们不能灵活的安排项目组长去做开场即根据现在的代码开场自我介绍被绑定给了小李而不能安排给其他人。为了解决上述的问题我们引入首先引入Leader接口相关代码和类图如下 public interface Leader {public void introduce();}public class Li implements Leader {Overridepublic void introduce() {System.out.println(大家好我是小李);}}public class Team {public void firstMeeting() {Leader li new Li();li.introduce();}} 具体类图如下 虽然上述的代码可以让我们安排给其他成员开场但是我们可以看出Team类同时依赖Leader接口和Li类并没有达到我们所期望的Team仅仅依赖于Leader接口的目的如何解决这个问题呢当然是引入Boss由Boss决定具体由谁担任项目组长。具体类图和代码如下 public interface Leader {public void introduce();}public class Li implements Leader {Overridepublic void introduce() {System.out.println(大家好我是小李);}}public class Team {public void firstMetting(Leader leader){leader.introduce();}}public class Boss {public void direct(){Leader leader new Li();Team team new Team();team.firstMetting(leader);}} 具体类图如下 通过以上代码和图示我们可以看出通过引入老板类我们将项目小组和具体由谁担任项目组长进行解耦。 对应上述例子我们再来讲解一下IoCIoC从字面上看分为控制和反转控制在上面的实例中就是具体由谁担任项目组长而反转就是将决定谁担任项目组长转移到Boss类中。通俗理解就是将接口的具体实现类Li的控制权从调用类Team中分离转交给第三方Boss决定。 到此为止IoC的概念我们就已经讲完了具体Spring中如何实现呢 一、第一个Spring程序 1、建立如下的项目结构 2、在项目的src下创建com.spring包下创建Student.java 1 package com.spring;2 /**3 * 4 * author Holly老师5 *6 */7 public class Student {8 private String name;9 private String sex;
10 public String getName() {
11 return name;
12 }
13 public void setName(String name) {
14 this.name name;
15 }
16 public String getSex() {
17 return sex;
18 }
19 public void setSex(String sex) {
20 this.sex sex;
21 }
22 Override
23 public String toString() {
24 return Student [name name , sex sex ];
25 }
26
27
28 } Student.java 3、在src下创建applicationContext.xml文件 1 ?xml version1.0 encodingUTF-8?2 beans xmlnshttp://www.springframework.org/schema/beans 3 xmlns:aophttp://www.springframework.org/schema/aop 4 xmlns:contexthttp://www.springframework.org/schema/context 5 xmlns:txhttp://www.springframework.org/schema/tx 6 xmlns:mvchttp://www.springframework.org/schema/mvc 7 xmlns:xsdhttp://www.w3.org/2001/XMLSchema 8 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance 9 xsi:schemaLocationhttp://www.springframework.org/schema/beans
10 http://www.springframework.org/schema/beans/spring-beans.xsd
11 http://www.springframework.org/schema/aop
12 http://www.springframework.org/schema/aop/spring-aop.xsd
13 http://www.springframework.org/schema/context
14 http://www.springframework.org/schema/context/spring-context.xsd
15 http://www.springframework.org/schema/tx
16 http://www.springframework.org/schema/tx/spring-tx.xsd
17 http://www.springframework.org/schema/mvc
18 http://www.springframework.org/schema/mvc/spring-mvc.xsd
19
20 !-- IOC依赖注入给对象注入数据 --
21 !-- 1.
22 bean节点相当于Student stuentnew Student();
23 bean的id就相当于对象名class是对象的类型全路径 --
24 bean idstudent classcom.spring.Student
25 !-- 1.1 为对象赋值代理对象通过setter方法赋值 --
26 !-- 1.2
27 property属性节点的name值必须和Student类的属性名保持一致
28 相当于 student.setName(扬名);
29 --
30 property namename value扬名/
31 property nameage value18/
32 /bean
33
34 !-- 2.创建HelloSpring的bean节点
35 HelloSpring helloSpringnew HelloSpring();
36 --
37 bean idhelloSpring classcom.spring.HelloSpring
38 !-- 2.1 给Student类型的stu对象赋值helloSpring.setStu(student); --
39 property namestu refstudent/
40
41 !-- 2.2赋值方式1给:helloSpring.setWho(Spring) --
42 property namewho
43 valueSpring/value
44 /property
45
46 !-- 2.3赋值方式2给helloSpring.setYou(holly);--
47 property nameyou valueholly/
48 /bean
49 /beans applicationContext.xml 4、在com.spring包下创建HelloSpring.java 1 package com.spring;2 3 public class HelloSpring {4 private Student stunull;5 private String whonull;6 private String younull;7 public Student getStu() {8 return stu;9 }
10 public void setStu(Student stu) {
11 this.stu stu;
12 }
13 public String getWho() {
14 return who;
15 }
16 public void setWho(String who) {
17 this.who who;
18 }
19 public String getYou() {
20 return you;
21 }
22 public void setYou(String you) {
23 this.you you;
24 }
25 /**
26 * 打印信息方法
27 */
28 public void print(){
29 System.out.println(Hellothis.getWho());
30 System.out.println(you是this.getYou());
31 }
32
33 } HelloSpring.java 5、在com.test包下创建Test.java 运的效果 1 package com.test;2 3 import org.springframework.context.ApplicationContext;4 import org.springframework.context.support.ClassPathXmlApplicationContext;5 6 import com.spring.HelloSpring;7 8 public class Test {9
10 /**
11 * param args
12 */
13 public static void main(String[] args) {
14 //1.读取xml文件
15 ApplicationContext acnew ClassPathXmlApplicationContext(applicationContext.xml);
16
17 /*2.通过ApplicationContext对象的getBean(Xxx)
18 * 获取xml文件中bean的id为Xxx的节点对象
19 */
20 HelloSpring hs(HelloSpring) ac.getBean(helloSpring);
21
22 //3.调用HelloSpring中的print方法
23 hs.print();
24
25 //4.打印HelloSpring中类型为Student的stu对象的值
26 System.out.println(hs.getStu());
27 }
28
29 } Test.java 二、使用IOC注入Dao 1、创建如下项目结构 2、在com.entity包下创建Classes.java 1 package com.entity;2 3 public class Classes {4 private int cid;5 private String cname;6 7 public Classes() {8 }9
10 public Classes(int cid, String cname) {
11 this.cid cid;
12 this.cname cname;
13 }
14
15 public int getCid() {
16 return cid;
17 }
18
19 public void setCid(int cid) {
20 this.cid cid;
21 }
22
23 public String getCname() {
24 return cname;
25 }
26
27 public void setCname(String cname) {
28 this.cname cname;
29 }
30
31 Override
32 public String toString() {
33 return Classes [cid cid , cname cname ];
34 }
35
36
37 } Classes.java 3、在com.entity包下创建Student.java 1 package com.entity;2 /**3 * 学生表4 * author Dell5 *6 */7 public class Student {8 private String sid;9 private String sname;
10 private String sex;
11 private Classes cla;
12
13 public Student() {
14 }
15 public Student(String sid, String sname, String sex, Classes cla) {
16 this.sid sid;
17 this.sname sname;
18 this.sex sex;
19 this.cla cla;
20 }
21 public String getSid() {
22 return sid;
23 }
24 public void setSid(String sid) {
25 this.sid sid;
26 }
27 public String getSname() {
28 return sname;
29 }
30 public void setSname(String sname) {
31 this.sname sname;
32 }
33 public String getSex() {
34 return sex;
35 }
36 public void setSex(String sex) {
37 this.sex sex;
38 }
39 public Classes getCla() {
40 return cla;
41 }
42 public void setCla(Classes cla) {
43 this.cla cla;
44 }
45 Override
46 public String toString() {
47 return Student [cla cla , sex sex , sid sid
48 , sname sname ];
49 }
50
51
52
53 } Student.java 4、在src下创建applicationContext.xml文件 1 ?xml version1.0 encodingUTF-8?2 beans xmlnshttp://www.springframework.org/schema/beans3 xmlns:aophttp://www.springframework.org/schema/aop 4 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance 5 xsi:schemaLocationhttp://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd 7 !-- 定义班级bean --8 bean idclasses classcom.entity.Classes9 property namecid value1/
10 property namecname valueTB13/
11 /bean
12
13 !-- 定义学生bean --
14 bean idstu classcom.entity.Student
15 property namesid value1/
16 property namesname valueholly/
17 property namesex value女/
18 !-- 注入班级bean --
19 !-- 注入方式1设置注入 --
20 property namecla refclasses/
21 /bean
22
23 /beans applicationContext.xml 5、在com.spring包下创建Test.java 1 package com.spring;2 3 import org.springframework.context.ApplicationContext;4 import org.springframework.context.support.ClassPathXmlApplicationContext;5 6 import com.entity.Student;7 8 public class Test {9
10 /**
11 * param args
12 */
13 public static void main(String[] args) {
14 //加载读取xml文件
15 ApplicationContext acnew ClassPathXmlApplicationContext(applicationContext.xml);
16
17 //通过配置文件的bean的id获取某个节点内容注意在要注入classes的student类中一定要有getter和setter方法
18 Student stu(Student) ac.getBean(stu);
19 System.out.println(stu);
20
21 }
22
23 } Test.java 6、运行效果如下 转载于:https://www.cnblogs.com/holly8/p/5532950.html
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/90346.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!