前言:
经过一系列被鄙视后,终于拿到一份还算满意的小offer,以后的日子就是不断学习的过程了,加油。
最近开始学习Spring框架,现将自己目前的学习状况以及自己的一部分理解总结一下。
Spring框架提供给用户的有两个大的主要功能:控制反转(IOC)或依赖注入(DI)和面向切面编程(AOP),当然还提供了其他的比如操作数据库的模板化以及事务管理、web开发中的Spring MVC等,这些以后会单独总结,但是最主要的还是依赖注入和面向切面编程。
一、Spring IOC以及DI的必要性
本篇文章总结控制反转(IOC)和依赖注入(DI),两者共同解决一个问题:对象耦合问题。下面举例说明。
在我们访问数据库时会写DAO,假设现在需要针对不同的数据库(mysql或oracle数据库)来写DAO,于是会有一个DAO接口类,并且会有针对不同数据库的相应的实现类(MysqlDaoImpl 和 OracleDaoImpl),如下所示:
DAO接口类:
package com.springframework.ioc; public interface MyDao{ //添加 public void addUser(); }
mysql实现类:
package com.springframework.ioc; public class MysqlDaoImpl implements MyDao{ @Override public void addUser(){ System.out.println("mysql add user..."); } }
oracle实现类:
package com.springframework.ioc; public class OracleDaoImpl implements MyDao{ @Override public void addUser(){ System.out.println("oracle add user..."); } }
这时上层service层要调用DAO,假设我的写法如下:
package com.springframework.ioc; public class MyService{ private MyDao myDao; public MyService(){ myDao = new MysqlDaoImpl(); } public void addUser(){ myDao.addUser(); } }
<constructor-arg ref = "oracle"/>
这种写法的缺点就是当我要换用作oracle数据库时需要修改MyService类,将myDao的创建改为
myDao = new OracleDaoImpl();
不符合开放-封闭原则, 于是我修改我的代码如下:
package com.springframework.ioc; public class MyService{ private MyDao myDao; public MyService(MyDao myDao){ this.myDao = myDao; } public void addUser(){ myDao.addUser(); } }
这样第三方在调用service层的addUser方法时的代码如下:
package com.springframework.ioc; public class Test{ public static void main(String[] args){ MyService myService = new MyService(new MysqlDaoImpl()); myService.addUser(); } }
这样当第三方需要的是oracle数据库的操作时,只需要将自己本身的代码修改为:
MyService myService = new MyService(new OracleDaoImpl());
将myDao对象的具体创建控制权交给第三方,而另外两房不需要关心,这就叫做控制反转。
以上是传统的编程做法,其实Spring框架也同样为我们解决了以上问题,使用的方式就是依赖注入方式。下面采用Spring框架来实现两个对象之间的解耦。
在Spring框架中,每一个类对象叫做一个bean,每一个bean有一个bean id和具体的实现类,Spring的IOC容器就是对这些bean进行管理和配置,将bean与bean之间的依赖通过配置文件或者注解的方式表现出来。
还是以以上的例子为例,为在xml文件中配置bean并将bean和bean之间的依赖进行配置如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd" default-lazy-init="true"> <!-- beans declare go here --> <!-- 通过默认构造器注入 --> <bean id="mysql" class="com.springframework.ioc.MysqlDaoImpl"/> <bean id="oracle" class="com.springframework.ioc.OracleDaoImpl"/> <!-- 通过含参构造器注入 --> <bean id = "myservice" class="com.springframework.ioc.MyService"> <constructor-arg ref = "mysql"/> </bean> </beans>
这样就将每个类作为bean注入到spring 的IOC容器中,然后第三方就可以获取bean并实例化bean,并调用其方法。如下所示:
package com.springframework.ioc; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class Test{ public static void main(String[] args){ //传统做法 /*MyService myService = new MyService(new OracleDaoImpl()); myService.addUser(); */ //使用spring后的做法 ApplicationContext context = new ClassPathXmlApplicationContext("ioc.xml"); MyService myService = (MyService)context.getBean("myservice"); myService.addUser(); } }
第三方如果想要调用的是oracle,则只需修改xml配置文件将
<constructor-arg ref = "mysql"/>
修改为:
<constructor-arg ref = "oracle"/>
即可。
将一个类通过xml配置文件的形式注入到另一个类中,实现了两个类之间的依赖,并且实现了解耦。两个类只需要关注自己的业务逻辑实现,无需管理其它类的实现。
二、Spring IOC&DI的实现原理
Spring管理bean和bean之间的依赖管理分别对应于对象的控制反转和依赖注入,控制反转即spring将xml文件进行解析,包括bean的id、class名字、别名、property属性等,解析为一个个的bean注册到IOC容器中;依赖注入即将bean通过反射的方式实例化bean,并通过三种注入方式将其他的bean注入进来,然后返回给第三方。
比如对于一个简单配置的spring 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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd"> <!-- beans declare go here --> <!-- 通过默认构造器注入 --> <bean id="mysql" class="com.springframework.ioc.MysqlDaoImpl"/> <bean id="oracle" class="com.springframework.ioc.OracleDaoImpl"/> </beans>
当Spring框架启动时,会对xml文件进行解析,按照节点首先解析的是
<bean id="mysql" class="com.springframework.ioc.MysqlDaoImpl"/>
在Spring框架中维护一个BeanDefinition来存储每一个bean节点的属性,如id、classname、propertity、autowire mode、initmethod name 、destroymethod name 等。
如下所示:
class BeanDefinition{ //bean 的id private String id; //bean 的classname private String className; //bean 的init method name private String initMethodName; //等等... }
每有一个BeanDefinition即有一个相应的对象,内部装载着以上介绍的bean的各种属性(id、className等),然后将这些BeanDefinition对象装载到IOC容器中,内部为键值为nbeanName,值为BeanDefinition的map表,如下所示:
/** Map of bean definition objects, keyed by bean name */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64);
这就完成了对xml文件的解析以及对BeanDefinition实例的注册。
当调用
MyService myService = (MyService)context.getBean("myservice");
时,
即为从map表中根据键值beanname(即bean的id)取出BeanDefinition实例,然后通过工厂方式或者构造函数反射机制创建bean实例,然后对beandefinition中的property属性进行解析,并通过set方法或者默认构造函数实现其他bean实例的注入。
这样就将每一个类以及类与类之间的依赖以bean的形式交给Spring的IOC容器来管理。
详细的IOC&DI的源代码解析或者原理解析可以参考这篇文章 http://www.cnblogs.com/ITtangtang/p/3978349.html。
参考:
http://www.importnew.com/13619.html
http://www.cnblogs.com/xdp-gacl/p/4249939.html
www.cnblogs.com/ITtangtang/p/3978349.html
相关推荐
少儿编程scratch项目源代码文件案例素材-直升机飞行.zip
wanjunshe_Python-Tensorflow_12888_1745868924470
健康监测_Android开发_BLE蓝牙通信_心率数据采集与存储_基于小米手环2的实时心率监测应用_支持后台长时间运行的心率记录工具_可导出SQLite数据库的心率数据分析系统_适
少儿编程scratch项目源代码文件案例素材-种花模拟器.zip
嵌入式系统开发_FreeRTOS实时操作系统_STM32F103C8T6微控制器_OLED显示屏_DHT11温湿度传感器_多任务调度_多级菜单设计_万年历算法_电子闹钟功能_参数配
基于python实现的粒子群的VRP(车辆配送路径规划)问题建模求解+源码+项目文档+算法解析,适合毕业设计、课程设计、项目开发。项目源码已经过严格测试,可以放心参考并在此基础上延申使用,详情见md文档 算法设计的关键在于如何向表现较好的个体学习,标准粒子群算法引入惯性因子w、自我认知因子c1、社会认知因子c2分别作为自身、当代最优解和历史最优解的权重,指导粒子速度和位置的更新,这在求解函数极值问题时比较容易实现,而在VRP问题上,速度位置的更新则难以直接采用加权的方式进行,一个常见的方法是采用基于遗传算法交叉算子的混合型粒子群算法进行求解,这里采用顺序交叉算子,对惯性因子w、自我认知因子c1、社会认知因子c2则以w/(w+c1+c2),c1/(w+c1+c2),c2/(w+c1+c2)的概率接受粒子本身、当前最优解、全局最优解交叉的父代之一(即按概率选择其中一个作为父代,不加权)。 算法设计的关键在于如何向表现较好的个体学习,标准粒子群算法引入惯性因子w、自我认知因子c1、社会认知因子c2分别作为自身、当代最优解和历史最优解的权重,指导粒子速度和位置的更新,这在求解函数极值问题时比较容易实现,而在VRP问题上,速度位置的更新则难以直接采用加权的方式进行,一个常见的方法是采用基于遗传算法交叉算子的混合型粒子群算法进行求解,这里采用顺序交叉算子,对惯性因子w、自我认知因子c1、社会认知因子c2则以w/(w+c1+c2),c1/(w+c1+c2),c2/(w+c1+c2)的概率接受粒子本身、当前最优解、全局最优解交叉的父代之一(即按概率选择其中一个作为父代,不加权)。
scratch少儿编程逻辑思维游戏源码-猫猫粉碎.zip
scratch少儿编程逻辑思维游戏源码-蓝胡子.zip
scratch少儿编程逻辑思维游戏源码-美食大亨.zip
scratch少儿编程逻辑思维游戏源码-洛克人.zip
scratch少儿编程逻辑思维游戏源码-龙冲刺.zip
思幻个人引导页V2.2版本11月29日更新.zip
scratch少儿编程逻辑思维游戏源码-骑士风斩法.zip
移动应用开发_H5CSS3ionicng-cordovaMVVM模式_基于HTML5和CSS3技术实现多页面布局ionic指令数据绑定ui-route单页跳转调用手机
少儿编程scratch项目源代码文件案例素材-植物大战僵尸创造版 Ver. 1.0.3.zip
scratch少儿编程逻辑思维游戏源码-日落(2).zip
动态星空背景个人主页(带后台).zip
scratch少儿编程逻辑思维游戏源码-迷雾森林:诞生 3.2 起源觉醒.zip
lib文件
影剧院音乐厅微信小程序源码,包括资讯动态,演出信息,艺术教育,经典 剧目,商务合作,关于我们,公益演出预约,商业演出预约,演出日历,我的今日预约,我的预约码,后台预约管理,后台预约核销,后台CMS内容管理等功能模块。是一个数字化的艺术殿堂公共平台,无需下载安装,让您能够随时随地便捷地走近乐团、走近交响乐 演出预约管理:开始/截止时间/人数均可灵活设置,可以自定义客户预约 填写的数据项 演出预约凭证:支持线下到场后校验签到/核销/二维码自助签到等多种方式 详尽的演出预约数据:支持预约名单数据导出Excel,打印