蘑菇大叔自留地

记录技术,分享技术


  • 首页

  • 归档

  • 搜索

如何编写自己的Spring Boot的Starter

发表于 2020-12-17   |   分类于 Spring Boot   |   暂无评论

Spring Boot的Starter是一个很优秀的东西。Starter为我们实现各种功能提供了一站式的接入方式。比如我们要在项目中使用JPA,那么直接引入spring-boot-starter-data-jpa就可以了。spring-boot-starter-data-jpa包括了引入jpa需要依赖的其他第三方包,以及要开启JPA的相关默认配置。Starter可以让我们对某个特性的需求做到开箱即用。

随着Spring Boot的流行,Starter越来越多了。官方的Starter命名都是spring-boot-starter-*这样的格式。*一般根据特性来指定。也有一些第三方Starter,但是第三方Starter一般命名都是thirdpartproject-spring-boot-starter,第三方的Starter不以spring-boot-starter开头。Starter是很好创建的,官方提供了指导:Creating Your Own Starter.

官方将自己的Starter分了下类: Starter 这里有三个Table. 占篇幅比较大,大家点前面链接进去看就好。
三大类分别是引入功能特性的Starter、为生产监控准备的Starter、以及可以自定义某种技术方案的Starter。
功能特性的Starter很好理解,比如前面提到的spring-boot-starter-data-jpa。为生产监控准备的Starter只有一个,就是spring-boot-starter-actuator、最后还有一类,这类主要是为了切换项目中的某些技术方案,比如默认容器是Tomcat,但是咱就喜欢jetty,那就引入spring-boot-starter-jetty。从spring-boot-starter-web中排除spring-boot-starter-tomcat。

Spring Boot官方提供了很多的Starter,每个Starter都有其各自的功能。我们用起来也爽歪歪。同时,我们也可以自定义一些Starter,提供出来给其他人用。

本文创建一个及其简单的Starter,这个Starter用来在启动的时候初始化Person对象。

首先,去 Spring Initializr 创建一个Spring Boot的项目(Starter仍旧是一个Spring Boot Application),如图1.

图1 创建基础项目

创建的过程中不需要添加依赖。同时,去掉生成的pom.xml中的下面代码:

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

这部分代码是用来打包的,他需要main方法,但是我们的Starter中是不需要main方法的。所以这个插件要去掉。

然后修改生成的启动类。修改后的代码如下:

    package cn.com.hanbinit.printspringbootstarter;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class PrintSpringBootStarterApplication {
        private static final Logger logger = LoggerFactory.getLogger(PrintSpringBootStarterApplication.class);
    
        @Value("${hanbin.name:}")
        private String name;
    
        @Bean
        public Person initPerson(){
            logger.info("我是自定义starter里面打印的,我只会在服务启动的时候初始化一下!");
            return new Person(name);
        }
    
    }

在同目录下创建了Person类,内容如下:

    package cn.com.hanbinit.printspringbootstarter;
    
    public class Person {
        private String name;
    
        public Person(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

最后,还有一个很重要的事情,在resources下建立META-INF目录,在目录下创建spring.factories文件,在文件中添加如下配置:

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    cn.com.hanbinit.printspringbootstarter.PrintSpringBootStarterApplication

到这里,这个Starter就创建完成了。这个时候我们就可以mvn clean install 或者 deploy给其他人用了。

下面创建一个demo application,引用了spring-boot-starter-web依赖,我们要在它中使用上面的Starter。

首先,在demo工程的pom.xml中添加依赖:

    <dependency>
        <groupId>cn.com.hanbinit</groupId>
        <artifactId>print-spring-boot-starter</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>

同时,修改启动类为下面的代码:

    package cn.com.hanbinit.demo;
    
    import cn.com.hanbinit.printspringbootstarter.Person;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    @SpringBootApplication
    public class DemoApplication {
    
        private final Person person;
    
        public DemoApplication(Person person) {
            this.person = person;
        }
    
        @GetMapping("/get_name")
        public String print(){
            return person.getName();
        }
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
    
    }

在application.properties中配置 hanbin.name=wo shi hanbin

访问http://localhost:8080/get_name,可得图2所示结果:

图2

关于Starter创建更多的可以多看看官方文档,也可以看看spring-boot-autoconfigure包的代码。Starter的技术基础还是Spring Boot的Auto-Configuration机制。

创建一个基本的Spring Boot应用

发表于 2020-12-11   |   分类于 Spring Boot   |   1 条评论

Spring Boot项目和传统的Maven项目有什么不同?

没有不同。Spring Boot 项目属于Maven项目,当然,也可以通过Gradle构建,本书设计项目主要使用Maven构建,后面会单独开一章专门将Gradle如何构建。

创建项目

打开网页 Spring Initializr,见图1。

图1

在前面打开的网页中按照图2所示填写,并点击网页底部的GENERATE按钮。
我们的第一个项目只需要完成一个简单的rest接口即可,所以上图右侧的dependecies我只选择了Spring Web。

图2

将下载的zip包解压缩到你希望它呆的地方,并导入你喜欢的IDE。这里使用的是Intellj Idea, 你也可以使用Eclipse或者Spring Tools。通过IDE查看项目结构,如图3所示, 可以看出它是一个标准的Maven工程, 并且提供了一些Spring Boot的基础文件,向我们展示了Spring Boot项目的基本结构。

图3

运行项目

DemoAppApplication.java文件里面包含有main方法,可以直接运行。
当你直接Run的时候, 在控制台中可以看到如下内容。

      .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::                (v2.4.0)
    
    2020-11-24 23:53:23.521  INFO 9592 --- [           main] c.c.hanbinit.demoApp.DemoAppApplication  : Starting DemoAppApplication using Java 15 on LAPTOP-740MHR3N with PID 9592 (D:\git\demoApp\target\classes started by hanbin in D:\git\demoApp)
    2020-11-24 23:53:23.521  INFO 9592 --- [           main] c.c.hanbinit.demoApp.DemoAppApplication  : No active profile set, falling back to default profiles: default
    2020-11-24 23:53:24.387  INFO 9592 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
    2020-11-24 23:53:24.398  INFO 9592 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
    2020-11-24 23:53:24.398  INFO 9592 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.39]
    2020-11-24 23:53:24.438  INFO 9592 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
    2020-11-24 23:53:24.448  INFO 9592 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 868 ms
    2020-11-24 23:53:24.568  INFO 9592 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
    2020-11-24 23:53:24.698  INFO 9592 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
    2020-11-24 23:53:24.708  INFO 9592 --- [           main] c.c.hanbinit.demoApp.DemoAppApplication  : Started DemoAppApplication in 1.473 seconds (JVM running for 2.145)

最后一行日志标识着我们的第一个Spring Boot项目已经成功启动了,只是我们的项目里面啥都没有。

添加接口

我们在DemoAppApplication.java中添加部分代码,如图4中红框标识。

图4

在浏览器中输入:http://localhost:8080/sayHello/jack, 可以看到图5所示结果,这标识着我们可以通过对这个项目做简单的代码改动,就可以提供出一个可以被访问的接口。

图5

下面讲下本文例子中使用到的几个注解。

  • @RestController 告诉我们这个类会提供一些API接口,这些接口默认会返回JSON格式的数据。不会像@Controller那样进行view间的跳转。
  • @GetMapping 告诉我们它修饰的这个方法会提供一个method为GET的接口,其中的内容是这个接口的URI。
  • @PathVariable 是用来取@GetMapping中的接口地址中的url传参的。
  • @SpringBootApplication 标记这个类里面的main方法启动的是一个Spring Boot应用,并且开启一些列的自动配置。

初识Spring Boot

发表于 2020-11-27   |   分类于 Spring Boot   |   暂无评论

Spring Boot 到底是什么东西?为什么这几年这么流行?我们都可以用它来做什么?

是什么

先到它的官网看看,点这里直通官网

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run". We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need minimal Spring configuration.

打开官网看到的第一句话就是上面的介绍,简单来说他就是小夸了一下自己。 言下之意你可以用 Spring Boot 创建一个独立的可以发布到生产环境使用的简单应用,你可以直接运行它,而不需要额外的服务器。并且在这个基础上,它还替你整合其他的 spring 和第三方的库,可以让你很方便的构建可用程序。 通过官网上简单的解释, 我们可以知道他就是一个开发框架, 只是它替你做了一些事情, 并且它认为这些事情是绝大多数如你一样的开发人员需要的。

为什么流行

国内从 2016 年开始,微服务架构大范围流行,各家公司都在搞微服务化。其中最流行的微服务框架就是 Spring 团队出品的 Spring Cloud 框架了。而 Spring Cloud 的基础就是 Spring Boot, Spring Cloud 的组件就是一个一个的 Spring Boot 项目。 同时,撇开 Spring Cloud,单独使用 Spring Boot 也是一个很好的开发框架,没有了以前使用 Spring Framework 时配置的若干 xml,也让前几年流行的“如何整合 SSH 框架”、“快速整合 SSM 框架”之类的博文快速消失了。 有两三年开发经验的 Java 开发人员就可以在很短的时间内使用 Spring Boot 做出一个看起来还不错的后台服务,对外提供若干可用的接口。 综合来看,Spring Boot 是一个可以作为微服务基础,且单打独斗的能力毫不逊色的优秀开发框架。它不流行谁流行呢?

Spring Boot 的特点

Spring Boot 因为它非常好的封装(约定),所以创建一个 Spring Boot 项目非常容易,且大部分的 Spring Boot 程序都子还需要做很少的额外配置。 使用 Spring Boot 创建的项目推荐使用 java -jar 的方式运行。当然,传统的 war 方式部署仍然是支持的。

这个系列讲什么

前面有提到,Spring Boot 是一个很能打的框架,而且还是微服务的基础。 本系列文章将重点介绍Spring Boot的各项特性,在写作的时候以官方文档为基础,适当辅以源码分析。

[leetcode-初级] 买卖股票的最佳时机 II

发表于 2020-09-23   |   分类于 Leetcode   |   暂无评论

题目:

给定一个数组,它的第  i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:

输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3

示例 2:

输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例 3:

输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

分析:

理解题目其实就是针对一个乱序的正数数组,在其中通过低买高卖的方式获得最大利润. 因为题目中这个数组对我们来说已知,所以在处理的过程中, 如果当天价格过高,我们可以选择不买入.
p1 天买入,p5 天卖出的利润 p5-p1 = (p5-p4) + (p4-p3) + (p3-p2) + (p2-p1). 由此可见, 我们只需要将每两天的盈利(差值)做相加即可. 在这个过程中, 如果盈利为负我们不处理. 可以得到源码.

源码

    class Solution {
        public int maxProfit(int[] prices) {
           int sum = 0;
           for(int i=1;i<prices.length; i++){
               int tmpProfit = prices[i] - prices[i-1];
               if(tmpProfit > 0){
                   sum += tmpProfit;
               }
           }
           return sum;
        }
    }

[leetcode-初级] 删除排序数组中的重复项

发表于 2020-09-22   |   分类于 Leetcode   |   暂无评论

题目

给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

示例  1:
给定数组 nums = [1,1,2], 函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1,
你不需要考虑数组中超出新长度后面的元素。
示例  2: 给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。

说明:

  • 为什么返回数值是整数,但输出的答案是数组呢?
  • 请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
  • 你可以想象内部操作如下:
        // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
        int len = removeDuplicates(nums);

        // 在函数里修改输入数组对于调用者是可见的。
        // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
        for (int i = 0; i < len; i++) {
            print(nums[i]);
        }

源码

    package cn.com.hanbinit.array;

    /**
     * 给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
     * 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
     */
    public class DelRepeatItemInSortedArray {
        public static int removeDuplicates(int[] nums) {
            int count = 0;
            // 这里从1开始,count从0开始和循环的值比较
            // 这里其实就是将nums[count]当作一个新的只知道第一个元素值的数组,
            // 只是这个nums[count]需要通过和num[i]去逐个比较,发现自己和nums[i]的元素不相同时,就将下一个index的元素值设置为当前的nums[i]的值
            for (int i = 1; i < nums.length; i++) {
                if (nums[i] != nums[count]) {
                    count++;
                    nums[count] = nums[i];
                }
            }
            return count + 1;
        }

        public static void main(String[] args) {
            // nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
            int[] nums = new int[]{0, 1, 1, 1, 2, 2, 2, 3, 3, 4};
            int len = removeDuplicates(nums);

            // 在函数里修改输入数组对于调用者是可见的。
            // 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
            for (int i = 0; i < len; i++) {
                System.out.print(nums[i] + "\t");
            }
        }
    }
123456

一个高端大气上档次的网站

27 文章
4 分类
25 标签
RSS
Gitee 知乎
© 2021 蘑菇大叔自留地
Typecho
主题 - NexT.Pisces
沪ICP备12020779号-2