什么是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.父元素依赖于spring-boot-starter-parent项目。 该父项目定义了许多有用的默认值,例如JDK 1.8的默认编译器级别。 在大多数情况下,你可以相信它知道自己在做什么。 例如,你可以忽略许多常见依赖项的版本号,并且SpringBootParent会将版本设置为兼容。 当你增加父级的版本号时,依赖项版本和默认值也会更改。
- 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干货