Bootstrap

Spring Boot starter

Spring Boot starter

Spring Boot大大简化了项目初始搭建以及开发过程spring boot 在配置上相比spring要简单许多, 其核心在于spring-boot-starter, 在使用spring boot来搭建一个项目时, 只需要引入官方提供的starter, 就可以直接使用, 免去了各种配置。starter简单来讲就是引入了一些相关依赖和一些初始化的配置。
Spring官方提供了很多starter,第三方也可以定义starter。为了加以区分,starter从名称上进行了如下规范:

  • Spring官方提供的starter名称为:spring-boot-starter-xxx

    例如Spring官方提供的spring-boot-starter-web

  • 第三方提供的starter名称为:xxx-spring-boot-starter

    例如由mybatis提供的mybatis-spring-boot-starter

starter原理

Spring Boot之所以能够帮我们简化项目的搭建和开发过程,主要是基于它提供的起步依赖和自动配置。
1.起步依赖
起步依赖,就是将具备某种功能的坐标打包到一起,可以简化依赖导入的过程,例如,导入spring-boot-starter-web这个starter,则和web开发相关相关的jar包都一起导入到项目中了
2.自动配置
自动配置,无须手动配置xml,自动配置并管理bean,可以简化开发过程。
自动配置涉及到

  • 基于java代码的bean配置
  • 自动配置条件依赖
  • bean参数获取
  • bean的发现
  • bean的加载

自定义starter

案例一:
开发starter

  1. 创建spring-boot-starter-parent的maven项目导入依赖
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
    </dependencies>
  1. 创建配置属性类HelloProperties(通常用于封装配置文件里面的配置参数的)
package cn.itcast.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
 * 读取yml文件属性参数
 */
@ConfigurationProperties(prefix = "hello")//如果报错可以先忽略
public class HelloProperties{
    private String name;
    private String address;
    @Override
    public String toString() {
        return "HelloProperties{" +
                "name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
}
  1. 创建服务类HelloService
package cn.itcast.service;
public class HelloService {
    private String name;
    private String address;
    public HelloService(String name, String address) {
        this.name = name;
        this.address = address;
    }
    public String sayHello(){
        return "你好!我的名字叫 " + name + ",我来自 " + address;
    }
}
  1. 创建自动配置类HelloServiceAutoConfiguration
package cn.itcast.config;

import cn.itcast.service.HelloService;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 配置类,基于java代码的bean配置
 */
@Configuration//表示当前是一个配置类
@EnableConfigurationProperties(HelloProperties.class)
public class HelloServiceAutoConfiguration {
    private  HelloProperties helloProperties;
//    通过构造方法注入配置属性对象HelloProperties
    public HelloServiceAutoConfiguration(HelloProperties helloProperties){
        this.helloProperties=helloProperties;
    }

//    实例化HelloService并放入ioc中
    @Bean
    @ConditionalOnMissingBean
    public HelloService helloService(){
        return new HelloService(helloProperties.getName(),helloProperties.getAddress());
    }
}
  1. 在resources目录下创建META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.itcast.config.HelloServiceAutoConfiguration
#EnableAutoConfiguration是一个注解作用是找到自动配置类

在这里插入图片描述

将该项目打成jar包
使用starter

  1. 创建新的maven工程

test-hello-spring-boot-starter
导入maven依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.mubai</groupId>
            <artifactId>hello-spring-boot-starter</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
  1. 创建application.yml文件
server:
  port: 8080
hello:
  name: mubai
  address: hefei
  1. 创建HelloController
package org.mubai.controller;

import cn.itcast.service.HelloService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/hello")
public class HelloController {
    //HelloService在我们自定义的starter中的自动配置类里面创建在ioc中已经完成了自动配置,所以此处可以直接注入
    @Autowired
    private HelloService helloService;

    @GetMapping("/say")
    public String sayHello(){
        return helloService.sayHello();
    }
}
  1. 创建启动类
package cn.itcast;

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

@SpringBootApplication
public class HelloApplication {
    public static void main(String[] args) {
        SpringApplication.run(HelloApplication.class,args);
    }
}

启动访问接口

案例二:通过自动配置来创建一个拦截器对象,通过此拦截器对象来实现记录日志功能。
开发starter

  1. 在hello-spring-boot-starter的pom.xml文件中追加如下maven坐标
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <optional>true</optional>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
  1. 自定义MyLog注解(不是所有的接口都拦截,只有加入这个注解的接口才会被拦截)
package cn.itcast.log;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 自定义日志注解
 */
@Target(ElementType.METHOD)//加在方法上的注解
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
    /**
     * 方法描述
     */
    String desc() default "";
}
  1. 自定义日志拦截器MyLogInterceptor
package cn.itcast.log;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.lang.reflect.Method;
/**
 * 自定义日志拦截器
 */
public class MyLogInterceptor extends HandlerInterceptorAdapter {
    private static final ThreadLocal<Long> startTimeThreadLocal=new ThreadLocal<>();//多线程访问共享变量的方法

    //在controller方法前执行此方法
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        HandlerMethod handlerMethod=(HandlerMethod)handler;
        Method method = handlerMethod.getMethod();//获取被拦截的方法对象
        MyLog annotation = method.getAnnotation(MyLog.class);//获得方法上有没有MyLog注解
        if(annotation!=null){
//            如果为空则说明没有获取到注解
            long l = System.currentTimeMillis();
            startTimeThreadLocal.set(l);//记录此刻时间
        }
        return true;//放行
    }
    //在controller方法后执行此方法
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();//获得被拦截的方法对象
        MyLog myLog = method.getAnnotation(MyLog.class);//获得方法上的注解
        if (myLog != null) {
            //方法上加了MyLog注解,需要进行日志记录
            long endTime = System.currentTimeMillis();
            Long startTime = startTimeThreadLocal.get();
            long optTime = endTime - startTime;

            String requestUri = request.getRequestURI();
            String methodName = method.getDeclaringClass().getName() + "." +
                    method.getName();
            String methodDesc = myLog.desc();
            System.out.println("请求uri:" + requestUri);
            System.out.println("请求方法名:" + methodName);
            System.out.println("方法描述:" + methodDesc);
            System.out.println("方法执行时间:" + optTime + "ms");
        }
        super.postHandle(request, response, handler, modelAndView);
    }
}
  1. 创建自动配置类MyLogAutoConfiguration,用于自动配置拦截器、参数解析器等web组件
package cn.itcast.config;

import cn.itcast.log.MyLogInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
* 配置类,用于自动配置拦截器、参数解析器等web组件
*/

@Configuration
public class MyLogAutoConfiguration implements WebMvcConfigurer {
   //注册自定义日志拦截器//此方法是接口中的方法,不需要配置bean,是专门用来添加拦截器的方法,拦截器会被自动的序列化,加入ioc中
   public void addInterceptors(InterceptorRegistry registry) {
       registry.addInterceptor(new MyLogInterceptor());
   }
}
  1. 在spring.factories中追加MyLogAutoConfiguration配置(告诉boot现在有一个这样的配置)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  cn.itcast.config.HelloServiceAutoConfiguration,\
  cn.itcast.config.MyLogAutoConfiguration
  1. 使用starter
;