Spring framework

Table of Contents

1. Spring 简介

The Spring Framework is an application framework and inversion of control container (IoC) for the Java platform. It help to decouple your project components' dependencies. It has become popular as an alternative to, replacement for, or even addition to the Enterprise JavaBeans (EJB) model.

Spring 有两个核心特性:依赖注入(Dependency Injection,DI)和面向切面编程(Aspect-Oriented Programming,AOP)。DI 能够让相互协作的软件组件保持松散耦合,而 AOP 允许你把遍布应用各处的功能分离出来形成可重用的组件。

参考:
Spring Framework Documentation: https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/index.html
Spring Tutorial: http://www.tutorialspoint.com/spring/index.htm
Spring 实现用户管理类的入门例子:http://blog.csdn.net/jnqqls/article/details/8622020

1.1. Spring 和工厂模式

有人说:反转控制容器(如 Spring 框架)是最好的工厂模式。各个类中不需要生成其他类的实例,完全由 XML 配置文件指定。Spring 的反转控制容器为你生成对象,把对象的引用塞给 Spring 管理的类中。这样,类之间就完全解耦了。但也有人说:虽然 Spring 美其名曰解藕了,但实际上是把原来工厂模式中的耦合性转移到了 XML 文件中。

1.2. 环境配置

Spring framework 依赖于 org.apache.commons.logging package,可从这里下载:http://commons.apache.org/proper/commons-logging/
Spring framework 的库文件可以从这里下载:http://repo.spring.io/release/org/springframework/spring/

下载上面的库文件后,把所有 jar 包配置到环境变量 CLASSPATH 中即可。

参考:http://www.tutorialspoint.com/spring/spring_environment_setup.htm

1.3. Hello World


下面演示利用 Spring 写一个简单的 Hello World 程序,消息"Hello World"将从 XML 文件中获取。

Following is the content of HelloWorld.java:

package com.xyz;

public class HelloWorld {
   private String message;

   public void setMessage(String message){
      this.message  = message;
   }

   public void getMessage(){
      System.out.println("Your Message : " + message);
   }
}

Following is the content of MainApp.java:

package com.xyz;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MainApp {
   public static void main(String[] args) {
      ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
      HelloWorld obj = (HelloWorld) context.getBean("MyFirstBean");
      obj.getMessage();
   }
}

Following is the content of Beans.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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id="MyFirstBean" class="com.xyz.HelloWorld">
       <property name="message" value="Hello World!"/>
   </bean>

</beans>

编译运行如下:

$ find .
.
./Beans.xml
./com
./com/xyz
./com/xyz/HelloWorld.java
./com/xyz/MainApp.java
$ export CLASSPATH=.:~/Downloads/spring-framework-4.1.0.RELEASE/libs/*:~/Downloads/commons-logging-1.2/commons-logging-1.2.jar
$ javac com/xyz/MainApp.java
$ java com/xyz/MainApp
Nov 14, 2015 9:42:56 PM org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@23ab930d: startup date [Tue Nov 14 21:42:56 CST 2015]; root of context hierarchy
Nov 14, 2015 9:42:56 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from class path resource [Beans.xml]
Your Message : Hello World!

参考:http://www.tutorialspoint.com/spring/spring_hello_world_example.htm

2. 配置 Bean

2.1. 实例化 Bean 的三种方式

2.1.1. 通过“属性注入”和“构造注入”创建对象

有 2 种注入方式可以创建对象:
1、属性注入:通过无参构造函数和 setter 方法注入;
2、构造注入:通过有参的构造函数注入。

1.3 中的例子就是通过“属性注入”创建对象的例子。

下面介绍如何通过“构造注入”来创建对象。假设你有下面类:

package examples;

public class ExampleBean {

    // Number of years to calculate the Ultimate Answer
    private int years;

    // The Answer to Life, the Universe, and Everything
    private String ultimateAnswer;

    public ExampleBean(int years, String ultimateAnswer) {
        this.years = years;
        this.ultimateAnswer = ultimateAnswer;
    }
}

构造注入形式 1:

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg type="int" value="7500000"/>
    <constructor-arg type="java.lang.String" value="42"/>
</bean>

构造注入形式 2:

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg index="0" value="7500000"/>
    <constructor-arg index="1" value="42"/>
</bean>

构造注入形式 3:

<bean id="exampleBean" class="examples.ExampleBean">
    <constructor-arg name="years" value="7500000"/>
    <constructor-arg name="ultimateAnswer" value="42"/>
</bean>

2.1.2. 通过静态方法创建对象

假设你有下面类:

public class ClientService {
    private static ClientService clientService = new ClientService();
    private ClientService() {}

    public static ClientService createInstance() {
        return clientService;
    }
}

指定 Bean 的 factory-method 属性可以通过静态方法来创建对象,如:

<bean id="clientService"
    class="examples.ClientService"
    factory-method="createInstance"/>

2.1.3. 通过工厂类创建对象

假设有下面工厂类:

public class DefaultServiceLocator {

    private static ClientService clientService = new ClientServiceImpl();

    public ClientService createClientServiceInstance() {
        return clientService;
    }
}

指定 Bean 的 factory-beanfactory-method 属性可以通过工厂类创建对象,如:

<bean id="serviceLocator" class="examples.DefaultServiceLocator">
    <!-- inject any dependencies required by this locator bean -->
</bean>

<bean id="clientService"
    <!-- factory-bean设置为工厂类bean的id  -->
    factory-bean="serviceLocator"
    <!-- factory-bean设置为工厂类中的方法  -->
    factory-method="createClientServiceInstance"/>

2.2. Bean scopes

Spring 中 Bean 的作用域如表 1 所示。

Table 1: Bean Scopes
Scope Description
singleton 在 Spring IoC 容器中仅存在一个 Bean 实例。这是默认值,即默认地所有 Bean 都是单例模式。
prototype 每次调用 getBean()时,都返回一个新的实例。
request 每个 HTTP 请求都会创建一个新的 Bean,该作用域仅适用于 WebApplicationContext 环境。
session 同一个 HTTP Session 共享一个 Bean,不同 Session 使用不同的 Bean,该作用域仅适用于 WebApplicationContext 环境。
application 在每个 ServletContext 中仅一个 Bean,该作用域仅适用于 WebApplicationContext 环境。
websocket 每个 WebSocket 中仅一个 Bean,该作用域仅适用于 WebApplicationContext 环境。

注:Bean 的默认 scope 为 singleton,所以定义 Bean 时 scope="singleton" 可以省略,如下面两个 Bean 定义是相同的:

<bean id="accountService" class="com.foo.DefaultAccountService"/>
<bean id="accountService" class="com.foo.DefaultAccountService" scope="singleton"/>

参考:https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/core.html#beans-factory-scopes

3. Aspect-oriented Programming (AOP)

4. Spring MVC

为什么使用 Spring MVC 呢?简单地说就是让开发者只关心核心业务的开发,框架帮你屏蔽跟业务开发无关的各类技术问题。

比如,可以使用 @Controller 标记一个类是 Spring MVC Controller 对象,然后使用 @RequestMapping 等注解定义 URL 请求和 Controller 方法之间的映射,这样的 Controller 就能被外界访问到。如:

@Controller
public class TestController {
     @RequestMapping(value="/product/{productId}",method = RequestMethod.GET)
     public String getProduct(@PathVariable("productId") String productId){
           System.out.println("Product Id : " + productId);
           return "hello";
     }
}

参考:
为什么要用Spring,SpringMVC?
通过Web开发演进过程了解一下为什么要有Spring?

5. Spring Boot

Spring Boot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化新 Spring 应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。 Spring Boot 的核心思想就是“约定大于配置”,多数 Spring Boot 应用只需要很少的 Spring 配置。 如果我们没有经历过 Spring 最开始繁琐的配置,可能体会不到为什么会有 Spring Boot 这个东西。

比如,要进行快速 Web 应用开发,引入 spring-boot-starter-web 即可,如:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

这个 starter 包含了 RESTful、Spring MVC 等的支持,且默认使用 Tomcat 作为内嵌的 Web 容器。在当前项目中运行 mvn spring-boot:run 就可以直接启用一个嵌套了 Tomcat 的 Web 应用。如果没有提供任何服务的 Cotroller,访问任何路径都会返回一个 Spring Boot 默认的错误页面。

如果你想使用 JAX-RS 和 Jersey 构建 RESTful 应用,可以使用 spring-boot-starter-jersey。Spring Boot 提供了各种各样的 starter,可参考 Spring Boot application starters

6. Spring Cloud

Spring Cloud 是目前微服务架构领域的翘楚。 Spring Cloud 可以看作是一套分布式服务治理的框架 ,包含了很多组件。如包含了来自 Netflix 公司的 Eureka (Service Discovery), Hystrix (Circuit Breaker), Zuul (Intelligent Routing) and Ribbon (Client Side Load Balancing)等组件。

参考:http://spring.io/projects/spring-cloud#overview

Author: cig01

Created: <2015-11-14 Sat>

Last updated: <2018-12-27 Thu>

Creator: Emacs 27.1 (Org mode 9.4)