Spring是一个开源的轻量级Java SE(Java 标准版本)/Java EE(Java 企业版本)开发应用框架,其目的是用于简化企业级应用程序开发。
a.Spring能帮我们根据配置文件创建及组装对象之间的依赖关系。
b.Spring 面向切面编程能帮助我们无耦合的实现日志记录,性能统计,安全控制。
c.Spring能非常简单的帮我们管理数据库事务。
d. Spring还提供了与第三方数据访问框架(如Hibernate、JPA)无缝集成,而且自己也提供了一套JDBC访问模板,来方便数据库访问。
e.Spring还提供与第三方Web(如Struts、JSF)框架无缝集成,而且自己也提供了一套Spring MVC框架,来方便web层搭建。
f.Spring能方便的与Java EE(如Java Mail、任务调度)整合,与更多技术整合(比如缓存框架)。
Spring架构图
包括Core、Beans、Context、EL模块。
spring-core 和 spring-beans 模块提供了框架中最基本的部分,包括控制反转和依赖注入。
spring-messaging 模块:Spring Framework 4 包含的模块,从 Spring 集成项目中抽象出来,比如 Message, MessageChannel, MessageHandler 及其他用来提供基于消息的基础服务。该模块还包括一组消息映射方法的注解,类似于基于编程模型 Spring MVC 的注解。
提供了对STOMP的支持,以及用于路由和处理来自WebSocket客户端的STOMP消息的注解编程模型。
Data Access/Integration 层由 JDBC, ORM, OXM, JMS, 和 Transaction 模块组成。
Web 层由 spring-web, spring-webmvc, spring-websocket, 和 spring-webmvc-portlet 组成 。
spring-websocket:为web应用提供的高效通信工具。 Spring 4.0提供了一个名为spring-websocket的新模块,以支持基于WebSocket的、客户端-服务器的双向通信,它与JSR-356Java WebSocket API兼容。另外,还提供了基于SockJS(对WebSocket的模拟)的回调方案,以适应不支持WebSocket协议的浏览器。
spring-test 模块支持通过组合 JUnit 或 TestNG 来进行单元测试和集成测试 。它提供了连续的加载 ApplicationContext 并且缓存这些上下文。它还提供了 mock object(模仿对象),您可以使用隔离测试你的代码。
IoC不是一种技术,只是一种思想,一个重要的面向对象编程的法则,它能指导我们如何设计出松耦合、更优良的程序。
-为何是反转,哪些方面反转了:有反转就有正转,传统应用程序是由我们自己在对象中主动控制去直接获取依赖对象,也就是正转;而反转则是由容器来帮忙创建及注入依赖对象;为何是反转?因为由容器帮我们查找及注入依赖对象,对象只是被动的接受依赖对象,所以是反转;哪些方面反转了?依赖对象的获取被反转了。
DI—Dependency Injection,即“依赖注入”:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。
Dependency Injection 和 Inversion of Control 其实就是一个东西的两种不同的说法而已。本质上是一回事。
Dependency Injection 是一个程序设计模式和架构模型, 一些时候也称作 Inversion of Control,尽管在技术上来讲,Dependency Injection 是一个 Inversion of Control 的特殊实现,Dependency Injection 是指一个对象应用另外一个对象来提供一个特殊的能力,例如:把一个数据库连接以参数的形式传到一个对象的结构方法里面而不是在那个对象内部自行创建一个连接。
Inversion of Control 和 Dependency Injection 的基本思想就是把类的依赖从类内部转化到外部以减少依赖。 应用Inversion of Control,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用,传递给它。也可以说,依赖被注入到对象中。所以,Inversion of Control 是,关于一个对象如何获取他所依赖的对象的引用,这个责任的反转。
“问题是,[他们]哪些方面的控制被反转?”这个问题由 Martin Fowler在他的 Inversion of Control (IoC) 网站在 2004 年提出。 Fowler 建议重新命名这个说法,使得他更加好理解,并且提出了 Dependency Injection(依赖注入) 这个新的说法。
IoC容器就是具有依赖注入功能的容器,IoC容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。应用程序无需直接在代码中new相关的对象,应用程序由IoC容器进行组装。在Spring中BeanFactory是IoC容器的实际代表者。
Spring IoC容器如何知道哪些是它管理的对象呢?这就需要配置文件,Spring IoC容器通过读取配置文件中的配置元数据,通过元数据对应用中的各个对象进行实例化及装配。一般使用基于xml配置文件进行配置元数据,而且Spring与配置文件完全解耦的,可以使用其他任何可能的方式进行配置元数据,比如注解、基于java文件的、基于属性文件的配置都可以。
由IoC容器管理的那些组成你应用程序的对象我们就叫它Bean, Bean就是由Spring容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别了。那IoC怎样确定如何实例化Bean、管理Bean之间的依赖关系以及管理Bean呢?这就需要配置元数据,在Spring中由BeanDefinition代表。
容器内部,这些 bean 定义表示为 BeanDefinition 对象,其中包含(其他信息)以下元数据:
什么是作用域呢?即“scope”,在面向对象程序设计中一般指对象或变量之间的可见范围。而在Spring容器中是指其创建的Bean对象相对于其他Bean对象的请求可见范围。
Spring提供“singleton”和“prototype”两种基本作用域,另外提供“request”、“session”、“global session”三种web作用域;Spring还允许用户定制自己的作用域。
作用域 | 描述 |
---|---|
单例(singleton) | (默认)每一个Spring IoC容器都拥有唯一的一个实例对象 |
原型(prototype) | 一个Bean定义可以创建任意多个实例对象 |
请求(request) | 一个HTTP请求会产生一个Bean对象,也就是说,每一个HTTP请求都有自己的Bean实例。只在基于web的Spring ApplicationContext中可用 |
会话(session) | 限定一个Bean的作用域为HTTPsession的生命周期。同样,只有基于web的Spring ApplicationContext才能使用 |
全局会话(global session) | 限定一个Bean的作用域为全局HTTPSession的生命周期。通常用于门户网站场景,同样,只有基于web的Spring ApplicationContext可用 |
应用(application) | 限定一个Bean的作用域为ServletContext的生命周期。同样,只有基于web的Spring ApplicationContext可用 |
单例Bean全局只有一个共享的实例,所有将单例Bean作为依赖的情况下,容器返回将是同一个实例。
Spring的单例Bean和与设计模式之中的所定义的单例模式是有所区别的。设计模式中的单例模式是将一个对象的作用域硬编码的,一个ClassLoader只有唯一的一个实例。 而Spring的单例作用域,是基于每个容器,每个Bean只有一个实例。这意味着,如果开发者根据一个类定义了一个Bean在单个的Spring容器中,那么Spring容器会根据Bean定义创建一个唯一的Bean实例。 单例作用域是Spring的默认作用域,下面的例子是在基于XML的配置中配置单例模式的Bean。
<bean id="accountService" class="com.foo.DefaultAccountService"/>
<!-- the following is equivalent, though redundant (singleton scope is the default) -->
<bean id="accountService" class="com.foo.DefaultAccountService" scope="singleton"/>
非单例的,原型的Bean指的就是每次请求Bean实例的时候,返回的都是新实例的Bean对象。也就是说,每次注入到另外的Bean或者通过调用getBean()来获得的Bean都将是全新的实例。 这是基于线程安全性的考虑,如果使用有状态的Bean对象用原型作用域,而无状态的Bean对象用单例作用域。
与其他的作用域相比,Spring是不会完全管理原型Bean的生命周期的:Spring容器只会初始化,配置以及装载这些Bean,传递给Client。但是之后就不会再去管原型Bean之后的动作了。 也就是说,初始化生命周期回调方法在所有作用域的Bean是都会调用的,但是销毁生命周期回调方法在原型Bean是不会调用的。所以,客户端代码必须注意清理原型Bean以及释放原型Bean所持有的一些资源。 可以通过使用自定义的bean post-processor来让Spring释放掉原型Bean所持有的资源。 在某些方面来说,Spring容器的角色就是取代了Java的new操作符,所有的生命周期的控制需要由客户端来处理。
构造函数----强依赖时
//
<constructor-arge value="">
//根据参数索引注入
<constructor-arg index value>
//根据参数类型进行注入
<constructor-arg type value>
//根据参数名进行注入
<constructor-arg name value>
Setter方法---可选依赖时
目标:开发时把业务逻辑与非业务逻辑分离,运行时可以将两部分整合。
no-aop缺点
AOP优点
AOP术语结构图
Aspect: 日志,安全等功能。 Join point:函数执行或属性访问 Advice:在某个函数执行点上要执行的切面功能 PointCut:匹配横切目标函数的表达式--即寻找哪些业务函数需要aop
before:函数执行之前 After returning:函数正常返回之后 After throwing:函数抛出异常之后 After finally:函数返回之后 Aroud:函数执行前后
非完整AOP实现,整合AOP与IoC
XML schema-based AOP 配置集中 @AspectJ annotation-based AOP 配置分散,兼容AspectJ
1、 启用对@AspectJ的支持
Spring默认不支持@AspectJ风格的切面声明,使用如下配置:
<aop:aspectj-autoproxy/>
Spring就能发现@AspectJ风格的切面并且将切面应用到目标对象。
2、声明切面
package com.windcoder.springweb.AOP;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
* Description:
* User: WindCoder
* Date: 2017-09-20
* Time: 17:48 下午
*/
//使用@Aspect注解声明切面
@Aspect
public class LoggingAspect {
//@Before定义前置通知,execution定义切入点
@Before("execution(* com.windcoder.springweb.entity.*.*(..))")
public void arithmeticDoLog(JoinPoint jp){
System.out.println(jp.toString());
}
}
然后将该切面在配置文件中声明为Bean后,Spring就能自动识别并进行AOP方面的配置:
<bean id="loggingAspect" class="com.windcoder.springweb.AOP.LoggingAspect"></bean>
该切面就是一个POJO,可以在该切面中进行切入点及通知定义,如代码中的注释。
在Spring配置文件中,所以AOP相关定义必须放在aop:config标签下,该标签下可以有aop:pointcut、aop:advisor、aop:aspect标签,配置顺序不可变。 aop:pointcut:用来定义切入点,该切入点可以重用; aop:advisor:用来定义只有一个通知和一个切入点的切面; aop:aspect:用来定义切面,该切面可以包含多个切入点和通知,而且标签内部的通知和切入点定义是无序的;和advisor的区别就在此,advisor只包含一个通知和一个切入点。
Spring Framework Reference Documentation
网易JavaWbe微专业