什么是Spring? Java的基于组件的开发在这

 

通过优锐课核心java学习笔记中,我们可以看到,码了很多专业的相关知识, 分享给大家参考学习。

带有Spring Web示例的控件反转和依赖注入的教程简介

21世纪初出现的基于组件的框架中,Spring也许是最好的。 它极大地改善了开发人员在基于Java的应用程序中编写和交付基础结构代码的方式。 自成立以来,Spring被公认为是企业Java开发的领先框架。 作为端到端的应用程序框架,Spring反映了Java EE的某些功能,但它提供了功能和编程约定的组合,这些在其他地方都找不到。

本文介绍了Spring及其核心编程哲学和方法:控制反转和依赖注入。 还将开始使用Spring批注和一些动手的编码示例。

依赖注入和控制反转

Spring的核心思想是,可以将它们卸载到框架中,而不是自己管理对象关系。 控制反转(IOC)是用于管理对象关系的方法。 依赖注入是实现IOC的机制。 由于这两个概念相关但不同,因此让我们更仔细地考虑它们:

  • ·控制反转(IOC)的名称恰如其分:它反转了用于实现对象关系的传统控制层次结构。 关系不是由应用程序代码定义对象之间如何关联的,而是由框架定义的。 作为一种方法,IOC为对象关系引入了一致性和可预测性,但是它确实要求(作为开发人员)放弃一些细粒度的控制。
  • ·依赖项注入(DI)是一种机制,框架可以将依赖项“注入”到的应用程序中。 这是IOC的实际实施。 从某种意义上说,依赖注入取决于多态性,它允许根据框架中的配置更改引用类型的实现。 该框架注入变量引用,而不是在应用程序代码中手动实现它们。

JSR-330

Java世界中的许多地方一样,Spring最初是作为一种狂放的创新而开始的,一部分已被标准规范所吸收。 在这种情况下,JSR-330是Java标准。 关于JSR-330规范的好处是,你可以在其他地方使用它,并将在Spring之外的其他地方看到它的使用。 你可以不使用Spring而使用它。 但是,Spring给桌面带来了更多的好处。

示例1:Spring依赖项注入

通过使用它们可以最好地理解控制反转和依赖注入,因此我们将以一个快速的编程示例开始。

假设正在为汽车建模。 如果使用普通的Java建模,那么Car类上可能有一个接口成员来引用Engine接口,如清单1所示。

清单1.普通的旧Java中的对象关系

public Interface Engine() { ... }

public class Car {

  private Engine engine;

  public Engine getEngine() { ... }

  public void setEngine(Engine engine) { ... }}

清单1包含一个Engine类型的接口和一个具体Car类型的类,该类引用了Engine。 (请注意,在实际的编程场景中,这些文件将放在单独的文件中。)现在,当创建Carinstance时,将设置关联,如清单2所示。

清单2.使用Engine界面创建汽车

// ...Car newCar = new Car();Engine sixCylEngine = new InlineSixCylinderEngine();

newCar.setEngine(sixCylEngine );// Do stuff with the car

请注意,首先创建了Car对象。 然后,创建一个满足Engine接口的新对象,并将其手动分配给Car对象。 这就是对象关联在普通的旧Java中的工作方式。

Spring中建模类和对象

现在让我们看一下Spring中的相同示例。 在这里,可以执行清单3中所示的操作。Car类开始,但是在这种情况下,向其添加了一个注释:@Inject。

清单3.在Spring中使用@Inject批注的示例

public class Car {

  @Inject

  private Engine engine;

  // ...}

使用@Inject批注(或@Autowired,如果愿意的话)告诉Spring根据一组规则搜索上下文并将对象自动注入到引用中。

接下来,考虑清单4所示的@Component注释。

清单4. @Component批注

@Componentpublic class InlineSixCylinderEngine implements Engine{

  //...}

@Component注释类告诉Spring它可用于完成注入。 在这种情况下,将插入InlineSixCylEngine,因为它可用并且满足关联的接口要求。 在春季,这称为“自动接线”注射。 (有关Spring的@Autowired注释的更多信息,请参见下文。)

解耦作为设计原则

带有依赖项注入的控件倒置从代码中删除了具体的依赖项源。 程序中无处没有对引擎实现的硬编码引用。 这是作为软件设计原理的解耦示例。 将应用程序代码与实现分离开来可使的代码更易于管理和维护。 该应用程序不太了解其各个部分如何组合在一起,但是在应用程序生命周期的任何时候进行更改要容易得多。

@Autowired vs @Inject

@Autowired和@Inject做同样的事情。 但是,@ Inject是Java标准注释,而@Autowired是特定于Spring的。 它们都具有相同的目的,即告诉DI引擎使用匹配的对象注入字段或方法。 你可以在Spring中使用任何一个。

Spring框架概述

现在,已经看到了一些Spring代码,让我们来概述一下框架及其组件。 如所见,该框架包含四个主要模块,这些模块分为多个包。 Spring将为使用的模块提供相当大的灵活性

  • 核心容器
  • 核心
  • 语境
  • 表达语言
  • 面向方面的编程(AOP)
  • 行动计划
  • 方面
  • 仪器仪表
  • 资料存取与整合
  • JDBC
  • JPA / ORM
  • JMS
  • 交易次数
  • 网页
  • 网络/ REST
  • Servlet
  • 支柱

让我们开始使用两个更常用的Spring功能,而不是在这里介绍所有内容

启动一个新项目:Spring Boot

我们将使用Spring Boot创建一个示例项目,以用于演示Spring功能。 Spring Boot使启动新项目变得更加容易,将自己看到。 首先,请看下面显示的主类。 Spring Boot中,我们可以使用具有main()方法的主类,然后选择独立运行它,或者选择打包运行在Tomcat之类的容器中。

清单5列出了我们的主类的概述,它们将位于标准的src / main / java / hello位置。

清单5. Spring Boot的主类

package hello;

import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplicationpublic class Application {

 

    public static void main(String[] args) {

        SpringApplication.run(Application.class, args);

    }

}

请注意上述代码的两件事:首先,所有工作都抽象到框架中。 主类会启动应用程序,但它对应用程序的工作方式或功能一无所知。 其次,SpringApplication.run()完成启动应用程序并传递Application类本身的实际工作。 同样,应用程序所做的工作在这里并不明显。

@SpringBootApplication注释包装了一些标准注释,并告诉Spring查看组件主类所在的包。 在我们之前的示例中,对于汽车和发动机,这将允许Spring查找所有带有@Component和@Inject注释的类。 该过程本身称为组件扫描,可高度自定义。

可以使用标准的mvn全新安装来构建应用程序,并且可以使用Spring Boot目标(mvn spring-boot:run)运行该应用程序。 在此之前,让我们看一下该应用程序的pom.xml文件。

清单6.入门pom.xml

<groupId>com.javaworld</groupId>

    <artifactId>what-is-spring</artifactId>

    <version>1.0.0</version>

 

    <parent>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-parent</artifactId>

        <version>2.1.3.RELEASE</version>

    </parent>

 

    <dependencies>

    </dependencies>

 

    <properties>

        <java.version>1.8</java.version>

    </properties>

 

    <build>

        <plugins>

            <plugin>

                <groupId>org.springframework.boot</groupId>

                <artifactId>spring-boot-maven-plugin</artifactId>

            </plugin>

        </plugins>

    </build>

请注意上述代码中的两个重要功能:

  1. 1.父元素依赖于spring-boot-starter-parent项目。 该父项目定义了许多有用的默认值,例如JDK 1.8的默认编译器级别。 在大多数情况下,可以相信它知道自己在做什么。 例如,可以忽略许多常见依赖项的版本号,并且SpringBootParent会将版本设置为兼容。 当增加父级的版本号时,依赖项版本和默认值也会更改。
  2. 2. spring-boot-maven-plugin允许可执行JAR / WAR打包和就地运行(通过mvn spring-boot:run命令)。

Spring Web添加为依赖项

到目前为止,我们已经能够使用spring-boot来限制为启动和运行应用程序而进行的工作量。 现在让我们添加一个依赖项,看看我们能多快地在浏览器中获取内容。

清单7.将Spring Web添加到项目

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId></dependency>

Note

Spring将自动检测哪些文件已更改并相应地进行编译。 你只需执行mvn spring-boot:run即可进行更改。

既然我们已经完成了基本的项目设置,就可以为两个示例做好准备了。

示例2:使用Spring Web构建RESTful端点

我们已经使用spring-boot-starter-web引入了一些对构建Web应用程序有用的依赖项。 接下来,我们将为URL路径创建路由处理程序。 Spring的Web支持是Spring MVC(Model-View-Controller)模块的一部分,但请不要担心:Spring Web也为构建RESTful端点提供了全面而有效的支持。

用来处理URL请求的类称为控制器,如清单8所示。

清单8. Spring MVC REST控制器

package hello;

import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;import org.springframework.web.bind.annotation.RequestParam;

@Controllerpublic class GreetingController {

 

    @RequestMapping(value = "/hi", method = RequestMethod.GET)

    public String hi(@RequestParam(name="name", required=false, defaultValue="JavaWorld") String name, Model model) {

        return "Hello " + name;

    }

}

@Controller批注

@Controller注释将一个类标识为控制器。 标记为控制器的类也将自动识别为组件类,这使其成为自动装配的候选对象。 无论何时需要此控制器,都将其插入框架。 在这种情况下,我们将其插入MVC系统以处理请求。

控制器是一种特殊的组件。 它支持hi()方法上看到的@RequestMapping和@ResponseBody注释。 这些注释告诉框架如何将URL请求映射到应用程序。

此时,可以使用mvn spring-boot:run运行该应用程序。 当点击/ hi URL时,将收到类似``Hello,JavaWorld''的响应。

请注意,Spring是如何利用自动装配组件的基础,并交付了整个Web框架的。 使用Spring,不必显式地将任何东西连接在一起!

@Request批注

@RequestMapping允许定义URL路径的处理程序。 选项包括定义所需的HTTP方法,这是我们在本例中所做的。 离开RequestMethod关闭将指示程序处理所有HTTP方法类型。

@RequestParam参数注释使我们可以将请求参数直接映射到方法签名中,包括要求某些参数和定义默认值(如此处所做的那样)。 我们甚至可以使用@RequestBody参数注释将请求主体映射到一个类。

REST和JSON响应

如果要创建REST端点,并且想从该方法返回JSON,则可以使用@ResponseBody对该方法进行注释。 然后,响应将自动打包为JSON。 在这种情况下,将从方法中返回一个对象。

Spring Web上使用MVC

Struts相似,Spring Web模块可以轻松地用于真正的模型-视图-控制器设置。 在这种情况下,你将以给定的模板语言(如Thymeleaf)返回映射,而Spring将解析该映射,提供传递给它的模型并呈现响应。

3:使用JDBC的Spring

现在,让我们对请求处理程序做一些更有趣的事情:让我们从数据库中返回一些数据。 出于本示例的目的,我们将使用H2数据库。 幸运的是,Spring Boot开箱即用地支持内存中的H2 DB。

可以通过将H2 DB包含在pom.xml中来将其添加到应用程序中,如清单9所示。我们还将为spring-boot-starter-jdbc添加一个依赖项。 这带来了我们需要用Spring控制JDBC的东西。

清单9.向H2 DB添加Maven依赖项

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency>

    <groupId>com.h2database</groupId>

    <artifactId>h2</artifactId>

    <version>1.4.194</version></dependency>

接下来,将要配置数据库。 这是通过spring.database.properties文件完成的,该文件位于/ resources目录中。 清单10显示了如何在激活内存模式的情况下使用H2。

清单10. H2内存中的配置

 

driverClassName=org.hsqldb.jdbc.JDBCDriver

url=jdbc:hsqldb:mem:myDb

username=sa

password=sa

服务组件类

现在,我们可以开始使用数据库了。 就这么简单。 但是,基本的软件设计告诉我们永远不要通过视图层访问数据层。 在这种情况下,我们不想通过视图控制器访问JDBC支持。 我们需要一个服务组件。 在Spring Web中,我们使用@Service注释创建服务类。 与@Controller注释类似,使用@Service注释将类指定为一种@Component。 这意味着Spring会将其添加到DI上下文中,并且可以将其自动连接到控制器中。

注释组件

Spring提供了几种注释组件的方法。 指示可用于自动布线的类的最基本方法是通过@Componentannotation。 @Service注释执行相同的操作,但是指示类的特定类型。 你可以使用@Bean批注指定一种方法,该方法用于创建要自动装配的Bean。

清单11显示了一个简单的Service组件。

清单11.服务组件

package hello.service;

import org.springframework.stereotype.Service;

@Service("myService")public class MyService {

  public String getGreeting(){

    return "Hey There";

  }

public boolean addSong(String name) {

if (name.length() > 15){

  return false;

}

return true;

}

public List<String> getSongs() {

return new ArrayList();

}}

现在,我们可以从控制器访问服务类。 在清单12中,我们将其注入。

清单12.将MyService注入控制器

@Controllerpublic class GreetingController {

  @Inject

  private MyService myService;

    @RequestMapping(value = "/hi", method = RequestMethod.GET)

    public String hi(@RequestParam(name="name", required=false, defaultValue="JavaWorld") String name, Model model) {

        return myService.getGreeting() + name;

    }

}

现在控制器正在使用Service类。 注意Spring是如何允许我们使用相同的DI系统定义分层体系结构的。 我们可以在定义服务类可以使用的数据层时做同样的事情,并同时利用Spring对各种数据存储和数据存储访问方法的支持。

我们可以使用@Repository注释数据层类,如清单13所示,然后将其注入服务类中。 以同样的方式,@ Service允许我们定义服务层,现在我们以分离的方式定义数据层。

JdbcTemplate类

数据层比服务层需要更多的资源,因为它将与数据库进行通信。 Spring主要通过提供JdbcTemplate类来缓解这种情况。

清单13.仓库数据类

import org.springframework.jdbc.core.JdbcTemplate;

@Repositorypublic class MyDataObject {

  public void addName(String name){

    jdbcTemplate.execute("DROP TABLE names IF EXISTS");

    jdbcTemplate.execute("CREATE TABLE names("id SERIAL, name VARCHAR(255))");

    jdbcTemplate.update("INSERT INTO names (name) VALUES (?)", name);

  }

}

Spring将自动使用我们配置的内存中H2 DB。 注意jdbcTemplate如何消除了此类中的所有样板代码和错误处理代码。 尽管这是访问数据库的简化示例,但它使了解了Spring如何工作以连接应用程序层,并促进其他必需服务的使用。

结论

Spring是Java最先进,最完整的应用程序开发框架之一。 它使设置应用程序变得更加容易,使可以随着应用程序的增长轻松地引入所需的依赖关系,并且完全有能力逐步实现大批量的生产级使用。

很难反对在新的Java应用程序中使用Spring。 Spring平台的维护和发展充满活力,实际上,可能需要执行的任何任务都可以通过Spring完成。 使用该平台将为省去大量繁重的工作,并有助于确保的应用程序设计稳定可靠。 如果可以使用Spring简化的开发路径,那就去做吧。

 

> 喜欢这篇文章的可以点个赞,欢迎大家留言评论,记得关注我,每天持续更新技术干货、职场趣事、海量面试资料等等
 > 如果你对java技术很感兴趣也可以交流学习,共同学习进步。 
> 不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代

 

文章写道这里,欢迎完善交流。最后奉上近期整理出来的一套完整的java架构思维导图,分享给大家对照知识点参考学习。有更多JVM、Mysql、Tomcat、Spring Boot、Spring Cloud、Zookeeper、Kafka、RabbitMQ、RockerMQ、Redis、ELK、Git等Java干货

 

 

posted @ 2020-03-17 10:09  Today今  阅读(932)  评论(0编辑  收藏  举报