从零学习Spring

一、Spring简介

Spring是一个开源框架,它由Rod Johnson建立。它是为了解决企业应用开发的复杂性而建立的。Spring使用基本的JavaBean来完成之前只可能由EJB完成的事情。然而,Spring的用途不只限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用均可以从Spring中受益。 Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。前端

二、Spring体系结构

Spring 有可能成为全部企业应用程序的一站式服务点,然而,Spring 是模块化的,容许你挑选和选择适用于你的模块,没必要要把剩余部分也引入。下面的部分对在 Spring 框架中全部可用的模块给出了详细的介绍。java

Spring 框架提供约 20 个模块,能够根据应用程序的要求来使用。程序员

其中有七大主要的模块web

2.一、核心容器

核心容器由spring-core,spring-beans,spring-context,spring-context-support和spring-expression(SpEL,Spring表达式语言,Spring Expression Language)等模块组成,它们的细节以下:spring

  • spring-core模块提供了框架的基本组成部分,包括 IoC 和依赖注入功能。数据库

  • spring-beans 模块提供 BeanFactory,工厂模式的微妙实现,它移除了编码式单例的须要,而且能够把配置和依赖从实际编码逻辑中解耦。express

  • context模块创建在由core和 beans 模块的基础上创建起来的,它以一种相似于JNDI注册的方式访问对象。Context模块继承自Bean模块,而且添加了国际化(好比,使用资源束)、事件传播、资源加载和透明地建立上下文(好比,经过Servelet容器)等功能。Context模块也支持Java EE的功能,好比EJB、JMX和远程调用等。ApplicationContext接口是Context模块的焦点。spring-context-support提供了对第三方库集成到Spring上下文的支持,好比缓存(EhCache, Guava, JCache)、邮件(JavaMail)、调度(CommonJ, Quartz)、模板引擎(FreeMarker, JasperReports, Velocity)等。编程

  • spring-expression模块提供了强大的表达式语言,用于在运行时查询和操做对象图。它是JSP2.1规范中定义的统一表达式语言的扩展,支持set和get属性值、属性赋值、方法调用、访问数组集合及索引的内容、逻辑算术运算、命名变量、经过名字从Spring IoC容器检索对象,还支持列表的投影、选择以及聚合等。后端

它们的完整依赖关系以下图所示:设计模式

2.二、数据访问/集成

数据访问/集成层包括 JDBC,DAO,ORM,OXM,JMS 和事务处理模块,它们的细节以下:

(注:JDBC=Java Data Base Connectivity,ORM=Object Relational Mapping,OXM=Object XML Mapping,JMS=Java Message Service)

  • JDBC 模块提供了JDBC抽象层,它消除了冗长的JDBC编码和对数据库供应商特定错误代码的解析。

  • DAO 模块提供了对JDBC、Hibernate、Mybatis等DAO层支持。

  • ORM 模块提供了对流行的对象关系映射API的集成,包括JPA、JDO和Hibernate等。经过此模块可让这些ORM框架和spring的其它功能整合,好比前面说起的事务管理。

  • OXM 模块提供了对OXM实现的支持,好比JAXB、Castor、XML Beans、JiBX、XStream等。

  • JMS 模块包含生产(produce)和消费(consume)消息的功能。从Spring 4.1开始,集成了spring-messaging模块。。

  • 事务模块为实现特殊接口类及全部的 POJO 支持编程式和声明式事务管理。(注:编程式事务须要本身写beginTransaction()、commit()、rollback()等事务管理方法,声明式事务是经过注解或配置由spring自动处理,编程式事务粒度更细)

2.三、Web

Web 层由 Web,Web-MVC,Web-Socket 和 Web-Portlet 组成,它们的细节以下:

  • Web 模块提供面向web的基本功能和面向web的应用上下文,好比多部分(multipart)文件上传功能、使用Servlet监听器初始化IoC容器等。它还包括HTTP客户端以及Spring远程调用中与web相关的部分。。

  • Web-MVC 模块为web应用提供了模型视图控制(MVC)和REST Web服务的实现。Spring的MVC框架可使领域模型代码和web表单彻底地分离,且能够与Spring框架的其它全部功能进行集成。

  • Web-Socket 模块为 WebSocket-based 提供了支持,并且在 web 应用程序中提供了客户端和服务器端之间通讯的两种方式。

  • Web-Portlet 模块提供了用于Portlet环境的MVC实现,并反映了spring-webmvc模块的功能。

2.四、其余

还有其余一些重要的模块,像 AOP,Aspects,Instrumentation,Web 和测试模块,它们的细节以下:

  • AOP 模块提供了面向方面的编程实现,容许你定义方法拦截器和切入点对代码进行干净地解耦,从而使实现功能的代码完全的解耦出来。使用源码级的元数据,能够用相似于.Net属性的方式合并行为信息到代码中。

  • Aspects 模块提供了与 AspectJ 的集成,这是一个功能强大且成熟的面向切面编程(AOP)框架。

  • Instrumentation 模块在必定的应用服务器中提供了类 instrumentation 的支持和类加载器的实现。

  • Messaging 模块为 STOMP 提供了支持做为在应用程序中 WebSocket 子协议的使用。它也支持一个注解编程模型,它是为了选路和处理来自 WebSocket 客户端的 STOMP 信息。

  • 测试模块支持对具备 JUnit 或 TestNG 框架的 Spring 组件的测试。

三、Spring体系详解

3.一、Spring IoC 容器

Spring 容器是 Spring 框架的核心。容器将建立对象,把它们链接在一块儿,配置它们,并管理他们的整个生命周期从建立到销毁。Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。 IOC 容器具备依赖注入功能的容器,它能够建立对象,IOC 容器负责实例化、定位、配置应用程序中的对象及创建这些对象间的依赖。一般new一个实例,控制权由程序员控制,而"控制反转"是指new实例工做不禁程序员来作而是交给Spring容器来作。在Spring中BeanFactory是IOC容器的实际表明者。

Spring 提供了如下两种不一样类型的容器。

序号 容器 & 描述
1 Spring BeanFactory 容器,它是最简单的容器,给 DI 提供了基本的支持,它用 org.springframework.beans.factory.BeanFactory 接口来定义。BeanFactory 或者相关的接口,如 BeanFactoryAware,InitializingBean,DisposableBean,在 Spring 中仍然存在具备大量的与 Spring 整合的第三方框架的反向兼容性的目的。
2 Spring ApplicationContext 容器,该容器添加了更多的企业特定的功能,例如从一个属性文件中解析文本信息的能力,发布应用程序事件给感兴趣的事件监听器的能力。该容器是由 org.springframework.context.ApplicationContext 接口定义。

ApplicationContext 容器包括 BeanFactory 容器的全部功能,因此一般建议超过 BeanFactory。BeanFactory 仍然能够用于轻量级的应用程序,如移动设备或基于 applet 的应用程序,其中它的数据量和速度是显著。

最常被使用的 ApplicationContext 接口实现:

  • FileSystemXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你须要提供给构造器 XML 文件的完整路径。

  • ClassPathXmlApplicationContext:该容器从 XML 文件中加载已被定义的 bean。在这里,你不须要提供 XML 文件的完整路径,只需正确配置 CLASSPATH 环境变量便可,由于,容器会从 CLASSPATH 中搜索 bean 配置文件。

  • WebXmlApplicationContext:该容器会在一个 web 应用程序的范围内加载在 XML 文件中已被定义的 bean。

3.1.一、Spring Bean定义的三种方式

Spring容器启动配置(web.xml文件)

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring/applicationContext.xml</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
复制代码

1、基于XML的配置

适用场景:

  • Bean实现类来自第三方类库,如:DataSource等
  • 须要命名空间配置,如:context,aop,mvc等
<beans>
    <import resource=“resource1.xml” />//导入其余配置文件Bean的定义
    <import resource=“resource2.xml” />
    
    <bean id="userService" class="cn.lovepi.***.UserService" init-method="init" destory-method="destory"> 
    </bean>
    <bean id="message" class="java.lang.String">
        <constructor-arg index="0" value="test"></constructor-arg>
    </bean>
</beans>
复制代码

2、基于注解的配置

适用场景:

  • 项目中本身开发使用的类,如controller、service、dao等

一、在applicationContext.xml配置扫描包路径

<context:component-scan base-package="com.lovepi.spring"> 
    <context:include-filter type="regex" expression="com.lovepi.spring.*"/> //包含的目标类
    <context:exclude-filter type="aspectj" expression="cn.lovepi..*Controller+"/>   //排除的目标类
</context:component-scan>
复制代码
  1. 使用注解声明bean

Spring提供了四个注解,这些注解的做用与上面的XML定义bean效果一致,在于将组件交给Spring容器管理。组件的名称默认是类名(首字母变小写),能够本身修改:

  • @Component:当对组件的层次难以定位的时候使用这个注解
  • @Controller:表示控制层的组件
  • @Service:表示业务逻辑层的组件
  • @Repository:表示数据访问层的组件

3、基于Java类的配置

适用场景:

  • 须要经过代码控制对象建立逻辑的场景
  • 实现零配置,消除xml配置文件

步骤以下:

  • 使用@Configuration注解须要做为配置的类,表示该类将定义Bean的元数据
  • 使用@Bean注解相应的方法,该方法名默认就是Bean的名称,该方法返回值就是Bean的对象。
  • AnnotationConfigApplicationContext或子类进行加载基于java类的配置

3.1.二、Spring Bean 做用域

当在 Spring 中定义一个 bean 时,你必须声明该 bean 的做用域的选项。例如,为了强制 Spring 在每次须要时都产生一个新的 bean 实例,你应该声明 bean 的做用域的属性为 prototype。同理,若是你想让 Spring 在每次须要时都返回同一个bean实例,你应该声明 bean 的做用域的属性为 singleton。

Spring 框架支持如下五个做用域,分别为singleton、prototype、request、session和global session,5种做用域说明以下所示

做用域 描述
singleton 在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,默认值
prototype 每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,至关于执行newXxxBean()
request 每次HTTP请求都会建立一个新的Bean,该做用域仅适用于WebApplicationContext环境
session 同一个HTTP Session共享一个Bean,不一样Session使用不一样的Bean,仅适用于WebApplicationContext环境
global-session 通常用于Portlet应用环境,该运用域仅适用于WebApplicationContext环境

3.1.三、Spring Bean 生命周期

理解 Spring bean 的生命周期很容易。当一个 bean 被实例化时,它可能须要执行一些初始化使它转换成可用状态。一样,当 bean 再也不须要,而且从容器中移除时,可能须要作一些清除工做。

为了定义安装和拆卸一个 bean,咱们只要声明带有 init-method 和/或 destroy-method 参数的 。init-method 属性指定一个方法,在实例化 bean 时,当即调用该方法。一样,destroy-method 指定一个方法,只有从容器中移除 bean 以后,才能调用该方法。

Bean的生命周期能够表达为:Bean的定义——Bean的初始化——Bean的使用——Bean的销毁

3.1.四、Spring 依赖注入

使用了Spring框架以后,对象的实例再也不由调用者来建立,而是由Spring容器来建立,Spring容器会负责控制程序之间的关系。这样控制权便由应用代码转移到Spring容器,控制权发生了反转,这就是Spring的控制反转

从Spring容器来看,Spring容器负责将被依赖对象赋值给调用者的成员变量,这就至关于为调用者注入了它依赖的实例,这就是Spring的依赖注入

1、setter 注入

这是最简单的注入方式,假设有一个TestController,类中须要实例化一个TestService对象,那么就能够定义一个private的TestService成员变量,而后建立TestService的set方法(这是ioc的注入入口):

public class TestController {
    private TestService testService;

    //注入testService
    public void setTestService(TestService testService) {
        this.testService = testService;
    }

    public void test() {
        testService.test();
    }

}

复制代码
public class TestService {
    public void test(){
        System.out.println("测试方法");
    }
}

复制代码

spring的xml文件:

<bean id="testController111" class="com.test.day.TestController">
    <property name="testService" ref="testService"></property>
</bean>

<bean id="testService" class="com.test.day.TestService">

</bean>
复制代码

2、构造器注入

这种方式的注入是指带有参数的构造函数注入,看下面的例子,建立成员变量TestService,可是并未设置对象的set方法,因此就不能支持第一种注入方式,这里的注入方式是在TestController的构造函数中注入,也就是说在建立TestController对象时要将TestService传进来:

public class TestController {
    private TestService testService;

    public TestController(TestService testService){
        this.testService = testService;
    }

    public void test() {
        testService.test();
    }

}

复制代码
public class TestService {
    public void test(){
        System.out.println("测试方法");
    }
}

复制代码

spring的xml文件:

<bean id="testController" class="com.test.day.TestController">
    <constructor-arg  name="testService" index="0" ref="testService"></constructor-arg>
</bean>

<bean id="testService" class="com.test.day.TestService">
复制代码

3、静态工厂注入

静态工厂顾名思义,就是经过调用静态工厂的方法来获取本身须要的对象,为了让spring管理全部对象,咱们不能直接经过"工程类.静态方法()"来获取对象,而是依然经过spring注入的形式获取:

静态工厂类:

public class StaticFactory {
    //静态工厂
    public static final TestService getTestService(){
        return new TestService();
    }
}
复制代码
public class TestController {
    private TestService testService;

    //注入testService
    public void setTestService(TestService testService) {
        this.testService = testService;
    }

    public void test() {
        testService.test();
    }

}
复制代码
public class TestService {
    public void test(){
        System.out.println("测试方法");
    }
}

复制代码

spring的xml文件:

<bean id="testController" class="com.test.day.TestController">
    <property name="testService" ref="testService"></property>
</bean>

<!--注意这里注入的是静态工厂类-->
<bean id="testService" class="com.test.day.StaticFactory" factory-method="getTestService">

</bean>
复制代码

4、实例工厂注入

实例工厂的意思是获取对象实例的方法不是静态的,因此你须要首先new工厂类,再调用普通的实例方法:

实例工厂类:

public class ExamplesFactory {
    //实例工厂
    public TestService getTestService(){
        return new TestService();
    }
}

复制代码
public class TestController {
    private TestService testService;

    //注入testService
    public void setTestService(TestService testService) {
        this.testService = testService;
    }

    public void test() {
        testService.test();
    }

}
复制代码
public class TestService {
    public void test(){
        System.out.println("测试方法");
    }
}

复制代码

spring的xml配置文件:

<bean id="testController" class="com.test.day.TestController">
    <property name="testService" ref="testService"></property>
</bean>

<bean id="testService" factory-bean="examplesFactory" factory-method="getTestService">

</bean>

<bean id="examplesFactory" class="com.test.day.ExamplesFactory">

</bean>
复制代码

5、注解注入 目前使用最普遍的 @Autowired:自动装配,基于@Autowired的自动装配,默认是根据类型注入

public class TestController {
    @Autowired
    private TestService testService;

    public String test() {
        testService.test();
        return null;
    }

}

复制代码
public class TestService {
    public void test(){
        System.out.println("测试方法");
    }
}

复制代码

spring的xml配置文件:

<context:component-scan base-package="com.test.day">
        <context:include-filter type="regex" expression="com.test.day.*"/>
    </context:component-scan>
复制代码

提供一个测试方法:

public class Test {
    @org.junit.Test
    public void test(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("spring/spring-context.xml");
        TestController controller = ac.getBean(TestController.class);
        controller.test();

    }
}
复制代码

3.1.五、Spring Beans 自动装配

学会如何使用元素来声明 bean 和经过使用 XML 配置文件中的和元素来注入 。

Spring 容器能够在不使用和 元素的状况下自动装配相互协做的 bean 之间的关系,这有助于减小编写一个大的基于 Spring 的应用程序的 XML 配置的数量。

自动装配模式

下列自动装配模式,它们可用于指示 Spring 容器为来使用自动装配进行依赖注入。你可使用元素的 autowire 属性为一个 bean 定义指定自动装配模式。

模式 描述
no 这是默认的设置,它意味着没有自动装配,你应该使用显式的bean引用来连线。你不用为了连线作特殊的事。在依赖注入章节你已经看到这个了。
byName 由属性名自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byName。而后尝试匹配,而且将它的属性与在配置文件中被定义为相同名称的 beans 的属性进行链接。
byType 由属性数据类型自动装配。Spring 容器看到在 XML 配置文件中 bean 的自动装配的属性设置为 byType。而后若是它的类型匹配配置文件中的一个确切的 bean 名称,它将尝试匹配和链接属性的类型。若是存在不止一个这样的 bean,则一个致命的异常将会被抛出。
constructor 相似于 byType,但该类型适用于构造函数参数类型。若是在容器中没有一个构造函数参数类型的 bean,则一个致命错误将会发生。
autodetect Spring首先尝试经过 constructor 使用自动装配来链接,若是它不执行,Spring 尝试经过 byType 来自动装配。

1、Spring 自动装配 byName

这种模式由属性名称指定自动装配。Spring 容器看做 beans,在 XML 配置文件中 beans 的 auto-wire 属性设置为 byName。而后,它尝试将它的属性与配置文件中定义为相同名称的 beans 进行匹配和链接。若是找到匹配项,它将注入这些 beans,不然,它将抛出异常。

直接修改以前的setter注入的代码,只须要修改一下配置文件便可

<bean id="testController111" class="com.test.day.TestController" autowire="byName">
    <!--        <property name="testService" ref="testService"></property>-->
</bean>

<bean id="testService" class="com.test.day.TestService">

</bean>
复制代码

2、Spring 自动装配 byType

这种模式由属性类型指定自动装配。Spring 容器看做 beans,在 XML 配置文件中 beans 的 autowire 属性设置为 byType。而后,若是它的 type 刚好与配置文件中 beans 名称中的一个相匹配,它将尝试匹配和链接它的属性。若是找到匹配项,它将注入这些 beans,不然,它将抛出异常。

和上面的例子没有什么区别,除了 XML 配置文件改为“byType”。

<bean id="testController" class="com.test.day.TestController"  autowire="byType">
    <!--<property name="testService"  ref="testService"></property>-->
</bean>

<bean id="testService" class="com.test.day.TestService">

</bean>
复制代码

3、Spring 构造函数自动装配

这种模式与 byType 很是类似,但它应用于构造器参数。Spring 容器看做 beans,在 XML 配置文件中 beans 的 autowire 属性设置为 constructor。而后,它尝试把它的构造函数的参数与配置文件中 beans 名称中的一个进行匹配和连线。若是找到匹配项,它会注入这些 bean,不然,它会抛出异常。

修改一下Controller,使用构造器的方式

public class TestController {
    private TestService testService;

    public TestController(TestService testService){
        this.testService = testService;
    }

    public void test() {
        testService.test();
    }

}

复制代码

配置文件

<bean id="testController" class="com.test.day.TestController"  autowire="constructor">
    <!--<property name="testService"  ref="testService"></property>-->
</bean>

<bean id="testService" class="com.test.day.TestService">

</bean>
复制代码

3.二、Spring AOP

Spring 框架的一个关键组件是面向方面的编程(AOP)框架。面向方面的编程须要把程序逻辑分解成不一样的部分称为所谓的关注点。跨一个应用程序的多个点的功能被称为横切关注点,这些横切关注点在概念上独立于应用程序的业务逻辑。有各类各样的常见的很好的方面的例子,如日志记录、审计、声明式事务、安全性和缓存等。

AOP 术语

描述
Aspect 一个模块具备一组提供横切需求的 APIs。例如,一个日志模块为了记录日志将被 AOP 方面调用。应用程序能够拥有任意数量的方面,这取决于需求。
Join point 在你的应用程序中它表明一个点,你能够在插件 AOP 方面。你也能说,它是在实际的应用程序中,其中一个操做将使用 Spring AOP 框架。
Advice 这是实际行动以前或以后执行的方法。这是在程序执行期间经过 Spring AOP 框架实际被调用的代码。
Pointcut 这是一组一个或多个链接点,通知应该被执行。你可使用表达式或模式指定切入点正如咱们将在 AOP 的例子中看到的。
Introduction 引用容许你添加新方法或属性到现有的类中。
Target object 被一个或者多个方面所通知的对象,这个对象永远是一个被代理对象。也称为被通知对象。
Weaving Weaving 把方面链接到其它的应用程序类型或者对象上,并建立一个被通知的对象。这些能够在编译时,类加载时和运行时完成。

通知的类型

通知 描述
前置通知 在一个方法执行以前,执行通知。
后置通知 在一个方法执行以后,不考虑其结果,执行通知。
返回后通知 在一个方法执行以后,只有在方法成功完成时,才能执行通知。
抛出异常后通知 在一个方法执行以后,只有在方法退出抛出异常时,才能执行通知。
环绕通知 在建议方法调用以前和以后,执行通知。

1、基于XML

2、基于注解

搞个简单的例子

为了测试异常,改一下service

public class TestService {
    public void test(){
        System.out.println("测试方法");
        int i = 1 / 0;
    }
}

复制代码

添加一个切面类

@Aspect
@Component
public class LogAsp {
    private final static Logger logger = LoggerFactory.getLogger(LogAsp.class);

    // 声明一个切入点
    @Pointcut("execution(public * com.test.day.TestService.*(..))")
    public void aspect() {
    }

    @Before("aspect()")
    public void beforeAdvice(){
        logger.info("前置通知。。。");
    }

    @After("aspect()")
    public void afterAdvice(){
        logger.info("后置通知。。。");
    }

    @AfterReturning(pointcut = "aspect()", returning="retVal")
    public void afterReturningAdvice(Object retVal){
        logger.info("返回后通知。。。" );
    }

    @AfterThrowing(pointcut = "aspect()", throwing = "ex")
    public void AfterThrowingAdvice(Exception ex){
        logger.info("抛出异常后通知...");
    }
    
    // @Around("aspect()")
    // public Object aroundAdvice(ProceedingJoinPoint pjp){
    //     Object obj = null;
    //     try {
    //         Object[] args = pjp.getArgs();// 获得方法所需的参数
    //         logger.info("环绕通知:前置...");
    //         //明确调用业务层方法
    //         obj = pjp.proceed(args);
    //         logger.info("环绕通知:后置...");
    //         return obj;
    //     } catch (Throwable throwable) {
    //         logger.info("环绕通知:异常...");
    //         throw new RuntimeException(throwable);
    //     }finally {
    //         logger.info("环绕通知:最终...");
    //     }
    // }
}

复制代码

修改一下spring配置文件

<context:component-scan base-package="com.test.day">
    <context:include-filter type="regex" expression="com.test.day.*"/>
</context:component-scan>

<!--经过配置织入@Aspectj切面-->
<aop:aspectj-autoproxy expose-proxy="true"></aop:aspectj-autoproxy>
复制代码

注意:aop:aspectj-autoproxy 正常是须要配置在 spring-mvc.xml 中的,我是为了测试只有一个配置文件就放在一块儿了。

启动测试类,查看打印结果,么得问题

3.三、Spring 事务管理

一个数据库事务是一个被视为单一的工做单元的操做序列。这些操做应该要么完整地执行,要么彻底不执行。事务管理是一个重要组成部分,RDBMS 面向企业应用程序,以确保数据完整性和一致性。事务的概念能够描述为具备如下四个关键属性说成是 ACID:

  • 原子性:事务应该看成一个单独单元的操做,这意味着整个序列操做要么是成功,要么是失败的。

  • 一致性:这表示数据库的引用完整性的一致性,表中惟一的主键等。

  • 隔离性:可能同时处理不少有相同的数据集的事务,每一个事务应该与其余事务隔离,以防止数据损坏。

  • 持久性:一个事务一旦完成所有操做后,这个事务的结果必须是永久性的,不能因系统故障而从数据库中删除。

局部事物 vs. 全局事务

  • 局部事务是特定于一个单一的事务资源,如一个 JDBC 链接,而全局事务能够跨多个事务资源事务,如在一个分布式系统中的事务。

  • 局部事务管理在一个集中的计算环境中是有用的,该计算环境中应用程序组件和资源位于一个单位点,而事务管理只涉及到一个运行在一个单一机器中的本地数据管理器。局部事务更容易实现。

  • 全局事务管理须要在分布式计算环境中,全部的资源都分布在多个系统中。在这种状况下事务管理须要同时在局部和全局范围内进行。分布式或全局事务跨多个系统执行,它的执行须要全局事务管理系统和全部相关系统的局部数据管理人员之间的协调。

编程式 vs. 声明式

Spring 支持两种类型的事务管理:

  • 编程式事务管理 :这意味着你在编程的帮助下有管理事务。这给了你极大的灵活性,但却很难维护。

  • 声明式事务管理 :这意味着你从业务代码中分离事务管理。你仅仅使用注释或 XML 配置来管理事务。

3.四、Spring Web MVC 框架

MVC 框架提供了模型-视图-控制的体系结构和能够用来开发灵活、松散耦合的 web 应用程序的组件。MVC 模式致使了应用程序的不一样方面(输入逻辑、业务逻辑和 UI 逻辑)的分离,同时提供了在这些元素之间的松散耦合。

  • 模型封装了应用程序数据,而且一般它们由 POJO 组成。

  • 视图主要用于呈现模型数据,而且一般它生成客户端的浏览器能够解释的 HTML 输出。

  • 控制器主要用于处理用户请求,而且构建合适的模型并将其传递到视图呈现。

DispatcherServlet

Spring Web 模型-视图-控制(MVC)框架是围绕 DispatcherServlet 设计的,DispatcherServlet 用来处理全部的 HTTP 请求和响应。Spring Web MVC DispatcherServlet 的请求处理的工做流程以下图所示:

  • 用户发送请求至前端控制器DispatcherServlet
  • DispatcherServlet收到请求调用HandlerMapping处理器映射器。
  • 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(若是有则生成)一并返回给DispatcherServlet。
  • DispatcherServlet经过HandlerAdapter处理器适配器调用处理器
  • 执行处理器(Controller,也叫后端控制器)。
  • Controller执行完成返回ModelAndView
  • HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
  • DispatcherServlet将ModelAndView传给ViewReslover视图解析器
  • ViewReslover解析后返回具体View
  • DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)。
  • DispatcherServlet响应用户

上面所提到的全部组件,即 HandlerMapping、Controller 和 ViewResolver 是 WebApplicationContext 的一部分,而 WebApplicationContext 是带有一些对 web 应用程序必要的额外特性的 ApplicationContext 的扩展。

四、常见问题分析

4.一、BeanFactory和ApplicationContext有什么区别?

  • 一、BeanFactory和ApplicationContext是Spring的两大核心接口,均可以当作Spring的容器。其中ApplicationContext是BeanFactory的子接口,除了提供BeanFactory所具备的功能外,还提供了更完整的框架功能(国际化、访问资源、载入多个(有继承关系)上下文等)

  • 二、BeanFactroy采用的是延迟加载形式来注入Bean的,即只有在使用到某个Bean时(调用getBean()),才对该Bean进行加载实例化。这样,咱们就不能发现一些存在的Spring的配置问题。若是Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常。

  • 三、ApplicationContext,它是在容器启动时,一次性建立了全部的Bean。这样,在容器启动时,咱们就能够发现Spring中存在的配置错误,这样有利于检查所依赖属性是否注入。 ApplicationContext启动后预载入全部的单实例Bean,经过预载入单实例bean ,确保当你须要的时候,你就不用等待,由于它们已经建立好了。它还能够为Bean配置lazy-init=true来让Bean延迟实例化。

  • 四、相对于基本的BeanFactory,ApplicationContext 惟一的不足是占用内存空间。当应用程序配置Bean较多时,程序启动较慢。

4.二、Spring BeanFactory 与 FactoryBean 的区别?

  • BeanFactory是一个factory,是spring的IOC的工场,而FactoryBean是个bean,它们两个只是名字很类似。

  • BeanFactory是一个IOC工场,用于管理和建立Bean,它是IOC最基本的接口,为其余的IOC工场提供规范,不少其余的spring容器都实现了它,如ApplicationContext、XMLBeanFactory等。它提供了经过bean的名字获取实例、判断bean是否在工场中、判断是否为单例等方法。

  • 对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式相似

4.三、Spring如何处理线程并发问题?

  • 在Spring中,绝大部分Bean均可以声明为singleton做用域,由于Spring对一些Bean中非线程安全状态采用ThreadLocal进行处理,解决线程安全问题。

  • ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。同步机制采用了“时间换空间”的方式,仅提供一份变量,不一样的线程在访问前须要获取锁,没得到锁的线程则须要排队。而ThreadLocal采用了“空间换时间”的方式。

  • ThreadLocal会为每个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突。由于每个线程都拥有本身的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,能够把不安全的变量封装进ThreadLocal。

4.四、Spring 框架中都用到了哪些设计模式?

  • 工厂模式:BeanFactory就是简单工厂模式的体现,用来建立对象的实例;

  • 单例模式:Bean默认为单例模式。

  • 代理模式:Spring的AOP功能用到了JDK的动态代理和CGLIB字节码生成技术;

  • 模板方法:用来解决代码重复的问题。好比. RestTemplate, JmsTemplate, JpaTemplate。

  • 观察者模式:定义对象键一种一对多的依赖关系,当一个对象的状态发生改变时,全部依赖于它的对象都会获得通知被制动更新,如Spring中listener的实现--ApplicationListener。

4.五、Spring 同一个aspect,不一样advice的执行顺序?

没有异常状况下的执行顺序:

  • around before advice(环绕通知:前置)
  • before advice(前置通知)
  • target method execution (方法执行)
  • around after advice(环绕通知:后置)
  • after advice(后置通知)
  • afterReturning(返回后通知)

有异常状况下的执行顺序:

  • around before advice(环绕通知:前置)
  • before advice(前置通知)
  • target method execution(方法执行)
  • after advice(后置通知)
  • afterThrowing(抛出异常后通知)
  • throw exception(抛出异常)

持续更新中。。。

相关文章
相关标签/搜索