1.Spring的概念:
Spring是一个轻量级的DI和AOP容器框架。
(1)DI:称作依赖注入(Dependency Injection)(控制反转),当一个角色需要另一个角色的协助的时候,在传统的程序设计 中,通常由调用者来创建被调用者的实例,但是在Spring中创建被调用者将不再由调用者完成,因此,叫控制反转。
创建被调用者由Spring容器来完成,在容器实例化对象的时候,主动将被调用者(依赖对象)注入给调用对象,因此,叫依赖注入(获得依赖对象的过程由自身管理变为了由IOC容器主动注入)。
IOC:从系统实现角度来看,IOC容器先创建SessionFactory和DataSource等底层组件,然后将这些底层组件注入数据访问Dao组件,提供一个完整的Dao组件,并将此Dao组件注入给业务逻辑Service组件,从而提供一个完整的Service组件,而Service组件又被注入给控制器Action组件,Action组件负责拦截用户请求,将处理结果呈现给用户,这一系列的衔接都由Spring的IOC容器提供实现。(通过容器来管理对象数据的填充和对象之间的关联关系,例如,A需要填充某种类型的数据,A需要关联B等。)(默认采用单例模式)(通俗点说,就是不创建对象,以前我们要调用一个对象的方法,首先要new一个对象,但使用IOC容器,在代码中不直接与对象连接,而是在配置文件中描述使用哪个对象。容器负责将这些联系在一起)。
(2)AOP:Spring对面向切面编程提供了强有力的支持,通过它让我们将业务逻辑从应用服务(如事物管理)中分离出来,实 现了高内聚开发,应用对象只关注业务逻辑,不再负责其他系统问题(如日志、事务),Spring支持用户自定义切 面。
2. Spring的构成:
核心容器:
核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。
Spring 上下文:
Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
Spring AOP:
通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
Spring DAO:
JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
Spring ORM:
Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
Spring Web 模块:
Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
Spring MVC 框架:
MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
3. IOC容器的具体实现
(在采用面向对象方法设计的软件系统中,它的底层实现都是由N个对象组成的,所有的对象通过彼此的合作,最终实现系统的业务逻辑。)
(初期也许都是new对象去调用下一层,比如你在业务层new一个Dao类的对象,调用Dao层类的方法访问数据库 ,这样写是不对的,因为在业务层中是不应该还有具体对象,最多只能引用,如果有具体对象的存在,就耦合了(当那个对象不存在,我还要修改业务的代码!!))
IOC理论,用来实现对象之间的“解耦”:借助于“第三方(IOC容器)”实现具有依赖关系的对象之间的解耦。
IOC容器的对象实例化是通过配置文件来实现的,术语这叫注入。注入有settter方法注入和构造器注入,基于注释的注入。
Setter方法注入:
Public class UserBean{
Private String str;
Public void setStr(String str){
This.str = str;
}
.....
}
<bean id=”userBean” class=”UserBean”>
<!- - 为str设置一个字符串值- ->
<property name=”str” value=”hello user bean”></property>
</bean>
构造器注入:
Public class ConTestBean{
Private String str;
Private UserBean userBean;
Public ConTestBean(String str, UserBean userBean){
This.str = str; //包含这两个参数的构造方法
This.userBean = userBean;
}
}
<!- - 配置ConTestBean,采用构造方法注入属性- - >
<bean id=”conTestBean” class=”com.throne212.javaweb.ch17.ConTestBean”>
<!- - 需要指定构造方法参数的下标位置,从0开始- ->
<contructor-arg index=”0”>
<value>hello constract bean</value>
</constructor-arg>
<constructor-arg>
<ref bean=”userBean”/><!- -userBean为另外一个bean实例- ->
</constructor-arg>
</bean>
4.Spring的底层实现原理:
当ClassPathXmlApplicationContext("applicationContext.xml")这句话执行的时候,spring容器对象就被创建。这个对象会读取applicationContext.xml中配置的bean就会被创建,并且放入内存。具体是怎么创建的呢?依赖于我们的反射机制。
那么,spring是如何实现刚才的那些个调用呢?首先,通过dom4j将我们的配置文件读取,这时我们就可以解析到所有相关的类的全路径了。然后,它再利用反射机制通过如下代码完成类的实例化:类1=Class.forName("类1的全路径")。这时,我们就得到了类1。(这也是为啥当我们的类的全路径写错了会导致出现classNotfind的错误。)
当我们得到了类1以后,通过调用类1的set方法,将属性给对象进行注入。而且,需要遵循首字母大写的set规范。例如:我们的类中有个字段的属性为name那么set方法必须写成setName(name 的首字母要大写)否则会报一个属性找不到的错误:
public void setName(String name){
this.name= name;
}
对象创建后,我们将我们的对象id和我们的对象物理地址,一起存入类似于HashMap的容器中,然后呢,我们是如何获得我们需要的对象,然后执行对象中的方法呢?我们通过getBean的方法,通过对象Id获得对象的物理地址,得到对象,然后调用对象的方法,完成对方法的调用。
5. 选择使用Spring框架的原因?
1 非侵入式:支持基于POJO的编程模式,不强制性的要求实现Spring框架中的接口和继承Spring框架中的类。
2 IOC容器:IOC容器帮助应用程序管理对象以及对象之间的依赖关系,对象之间的依赖关系,如果发生了改变,只需要修改配 置文件,而不是修改代码。
3 AOP(面向切面编程):将所有的横切关注功能封装到切面(aspect)中,通过配置的方式将横切关注功能动态添加到目标代码 中,进一步实现了业务逻辑和系统服务之间的分离。
4 MVC:为Web表示层提供了更好的解决方案。
5 事务管理:Spring以宽广的胸怀接纳多种持久层技术,并且为其提供了声明式事务管理,在不需要任何一行代码的情况下就 能完成事务管理。