Java Spring MVC入门(五)依赖注入之理论部分
十一看家乡
十一回了趟老家,老家是一个小县城,最多算个四线城市,人均月工资估计2000——3000左右,房价大概在3800——5000左右。经济主要靠茶叶、贡菊等农林产品,最近几年浙江老板来投资开了一些工厂,也提供了一些工作机会。
茶余饭后和家中亲戚朋友聊天,话语中透露出生活的艰辛,现在基本是既要从事农业生产劳动,又要去周边工厂找点零工做,活也不好找,人多工作机会少。有的在工厂有固定工作的,工作时间长,假期少,劳动法里规定的假期福利在这里就是一纸空文,一放假还要去从事农业生产,为的是多赚点钱。
我听了之后心里久久不能平静,我从家乡出来已经有十几年了,十几年来这种情况好像一直从未改变,生存依旧是那样的艰辛,中国的底层劳动人民生活水平还需要提升。唯一改变的,是多了许多房子,那房子又是一座大山。
此时不由想起鲁迅的《故乡》
时候既然是深冬;渐近故乡时,天气又阴晦了,冷风吹进船舱中,呜呜的响,从篷隙向外一望,苍黄的天底下,远近横着几个萧索的荒村,没有一些活气。我的心禁不住悲凉起来了。
阿!这不是我二十年来时时记得的故乡?
.....
我躺着,听船底潺潺的水声,知道我在走我的路。我想:我竟与闰土隔绝到这地步了,但我们的后辈还是一气,宏儿不是正在想念水生么。我希望他们不再像我,又大家隔膜起来……然而
我又不愿意他们因为要一气,都如我的辛苦展转而生活,也不愿意他们都如闰土的辛苦麻木而生活,也不愿意都如别人的辛苦恣睢而生活。
他们应该有新的生活,为我们所未经生活过的。
为何需要依赖注入?
假设现在我们有这样的场景,A类要实现发邮件功能,那么代码可能会这样写:
class A { Mail myMail; public void AMethod()//一个方法 { myMail = new Mail(); myMail.sendMail(); } }
上面代码中,class A 内的AMethod方法体内直接new Mail() 创建对象,这样的写法是有问题的,假如此时由于业务需要,Mail类的构造函数发生了改变,创建对象的时候必须传参数“sendEmail” ,此时,项目中所有所有 new Mail() 都必须改为 new Mail(sendEmail) :
class A{ Mail myMail; public void AMethod()//一个方法 { String sendEmail = "lisan@163.com"; myMail = new Mail(sendEmail); myMail.sendMail(); } }
如果是小型项目那还好说,如果是大型项目,项目中可能有几千几万个地方都用到了"new Mail()",我们都要一一修改,那么将是一场噩梦。像上面的情况我们称为:Class A 对 Class Mail 产生了依赖,也可以说他们之间有强耦合。
为了解决上面的问题,我们改一改写法(工厂模式):
class A{ public void AMethod()//一个方法 { MailFactory mailFactory = new MailFactory(); Mail myMail = mailFactory.getEmail(); myMail.sendMail(); } } class MailFactory{ public Mail getEmail(){ return new Mail(); //String sendEmail = "lisan@163.com"; //return new Mail(sendEmail); } }
从上面的代码我们可以看出,我们不直接在A里面去创建Mail对象,而是在MailFactory类里的getEmail方法里去创建,A方法体内去调用这个方法获得对象。如果Mail类的构造函数有所变动,我们只要改MailFactory的getMail方法这一个地方即可,这样看起来比上一种写法强多了。但是这样的写法也不是完全没有问题的,假如此时MailFactory的getMail方法要加一个参数(当然这种情况不多见),那么Class A 里为了要加参数,还是要改代码。耦合依然存在。
根据上面两种写法我们可以看出,当某个Java对象(调用者),需要调用另外一个Java对象(被依赖对象)方法时,在传统模式下有两种做法:
1、原始做法
调用者主动创建被依赖对象,然后再调用被依赖方法
2、简单工厂模式
调用者先找到被依赖对象的工厂,然后通过主动通过工厂去获得被依赖对象,最后再调用被依赖方法。
第一种方法会导致调用者和被依赖对象类的强耦合,非常不利于代码维护和升级。
第二种方法解决了第一种方法的问题,不会产生强耦合,但是由于去主动通过工厂去获取被依赖对象,这就会带来调用组件与被依赖对象工厂的耦合。
为了彻底解决耦合问题,引入依赖注入(控制反转)设计模式。
依赖注入(控制反转)
由上面可以看出,第一和第二种方法都是主动获取被依赖对象,或多或少的会有一些耦合,那么如果调用者不去主动调用被依赖对象呢?改主动调用为被动接收呢?
依赖注入的本质就是改主动为被动,由主动调用请求改为被动接收。
在Java Spring中,被依赖的对象不再由程序员实例化,而是通过Spring容器帮我们new指定实例,并且将实例注入到需要该对象的类中。
使用Spring框架之后,调用者获取被依赖对象由原来主动获取变成了被动接受,由于由主动变为被动——于是我们称之为控制反转;从Spring容器角度来看,Spring容器负责将被依赖对象赋值给调用者的成员变量——相当于为调用者注入它依赖的实例,所以称之为依赖注入。
此篇为理论部分,下篇为实践部分。