栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringBoot学习笔记

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringBoot学习笔记

微服务阶段 javase:OOP

MySQL:持久化

html+css+js+jquery+框架:视图,框架不熟练,css不好

javaweb:独立开发MVC三层架构的网站:原始

ssm:框架:简化了我们的开发流程,配置也开始较为复杂;

在此之前项目打包都是war包,程序在Tomcat中运行

spring再简化:springBoot-jar包,内嵌Tomcat;微服务架构! 服务越来越多:springCloud

1.SpringBoot 初识 1.1 回顾什么是Spring

Spring是一个开源框架,2003 年兴起的一个轻量级的Java 开发框架,作者:Rod Johnson 。

Spring是为了解决企业级应用开发的复杂性而创建的,简化开发。

Spring是如何简化Java开发的

为了降低Java开发的复杂性,Spring采用了以下4种关键策略:

1、基于POJO的轻量级和最小侵入性编程,所有东西都是bean;
​
2、通过IOC,依赖注入(DI)和面向接口实现松耦合;
​
3、基于切面(AOP)和惯例进行声明式编程;
​
4、通过切面和模版减少样式代码,RedisTemplate,xxxTemplate;
1.2 什么是SpringBoot

学过javaweb的同学就知道,开发一个web应用,从最初开始接触Servlet结合Tomcat, 跑出一个Hello Wolrld程序,是要经历特别多的步骤;后来就用了框架Struts,再后来是SpringMVC,到了现在的SpringBoot,过一两年又会有其他web框架出现;你们有经历过框架不断的演进,然后自己开发项目所有的技术也在不断的变化、改造吗?建议都可以去经历一遍;

言归正传,什么是SpringBoot呢,就是一个javaweb的开发框架,和SpringMVC类似,对比其他javaweb框架的好处,官方说是简化开发,约定大于配置, you can “just run”,能迅速的开发web应用,几行代码开发一个http接口。

所有的技术框架的发展似乎都遵循了一条主线规律:从一个复杂应用场景 衍生 一种规范框架,人们只需要进行各种配置而不需要自己去实现它,这时候强大的配置功能成了优点;发展到一定程度之后,人们根据实际生产应用情况,选取其中实用功能和设计精华,重构出一些轻量级的框架;之后为了提高开发效率,嫌弃原先的各类配置过于麻烦,于是开始提倡“约定大于配置”,进而衍生出一些一站式的解决方案。

是的这就是Java企业级应用->J2EE->spring->springboot的过程。

随着 Spring 不断的发展,涉及的领域越来越多,项目整合开发需要配合各种各样的文件,慢慢变得不那么易用简单,违背了最初的理念,甚至人称配置地狱。Spring Boot 正是在这样的一个背景下被抽象出来的开发框架,目的为了让大家更容易的使用 Spring 、更容易的集成各种常用的中间件、开源软件;

Spring Boot 基于 Spring 开发,Spirng Boot 本身并不提供 Spring 框架的核心特性以及扩展功能,只是用于快速、敏捷地开发新一代基于 Spring 框架的应用程序。也就是说,它并不是用来替代 Spring 的解决方案,而是和 Spring 框架紧密结合用于提升 Spring 开发者体验的工具。Spring Boot 以约定大于配置的核心思想,默认帮我们进行了很多设置,多数 Spring Boot 应用只需要很少的 Spring 配置。同时它集成了大量常用的第三方库配置(例如 Redis、MongoDB、Jpa、RabbitMQ、Quartz 等等),Spring Boot 应用中这些第三方库几乎可以零配置的开箱即用。

简单来说就是SpringBoot其实不是什么新的框架,它默认配置了很多框架的使用方式,就像maven整合了所有的jar包,spring boot整合了所有的框架 。

Spring Boot 出生名门,从一开始就站在一个比较高的起点,又经过这几年的发展,生态足够完善,Spring Boot 已经当之无愧成为 Java 领域最热门的技术。

Spring Boot的主要优点:

为所有Spring开发者更快的入门

开箱即用,提供各种默认配置来简化项目配置

内嵌式容器简化Web项目

没有冗余代码生成和XML配置的要求

真的很爽,我们快速去体验开发个接口的感觉吧!

1.3 微服务架构

微服务是一种架构风格,他要求我们在开发一个应用的时候,这个应用必须建成一系列小服务组合,可以通过http方式进行通信。

所谓微服务加购,就是打破之前all in one的架构方式,把每个功能元素独立出来,把独立出来的功能元素的动态组合,需要的功能元素才去拿来组合,需要多一些可以整合多个功能元素,所以微服务架构是对功能元素进行赋值,而没有对整个应用进行复制,这样做的好处是:

节省了调用资源 每个功能元素的服务都是一个可替换的,可独立升级的软件代码 程序核心:高内聚(在划分模块时,要把功能关系紧密的放到一个模块中) 低耦合(模块之间的联系越少越好,接口越简单越好)

论文地址:Microservices

构建一个个功能独立的微服务应用单元,可以使用springboot,可以帮我们快速构建一个应用 大型分布式网络服务的调用,这部分springcloud来完成,实现分布式 在分布式中间,进行流式数据计算,批处理,我们有spring cloud data flow spring为我们想清楚了整个开始构建应用到大型分布式应用全流程方案

2,第一个SpringBoot 程序

通过Idea创建SpringBoot项目, 新建一个项目, 选择Spring Initalizr.

idea帮我们创建好了项目之后,在项目目录下会有一个主程序的启动入口, 我们直接运行这个主程序。 第一个SpringBoot 程序就跑起来了。

@SpringBootApplication
public class Boot01Application {
​
    public static void main(String[] args) {
//        SpringApplication app = new SpringApplication();
        SpringApplication.run(Boot01Application.class, args);
    }
}

写个接口玩一玩?

新建controller包, 要和项目的主程序在同一目录!

新建我们自定义的Controller类。

@RestController
@RequestMapping("/user")
public class MyController {
​
    @RequestMapping("/getUserList")
    public String getUserList() throws JsonProcessingException {
        ArrayList user = new ArrayList<>();
        user.add("zyd");
        user.add("万众期待的SpringBoot");
        user.add("老子终于学到SpringBoot了!!");
        user.add("zyd的第一个SpringBoot程序");
        ObjectMapper mapper = new ObjectMapper();
        return mapper.writevalueAsString(user);
    }
}
​

之后,不需要做任何配置,重新启动SpringBoot主程序即可!

SpringBoot 内嵌了tomcat , SpringMVC,将服务启动在http://localhost:8080

打开浏览器,输入http://localhost:8080/user/getUserList, 就可以看到接口返回的结果了。是不是用SpringBoot开发一个接口特别爽,不需要我们使用xml文件去配置了,从头到尾,我们只新建了一个包,写了一个接口, 其余的啥也不用配置,SpringBoot 都帮我们配置好了,爽~

3,SpringBoot自动配置原理

从SpringBoot 的程序入口上来看,主类上会有@SpringBootApplication 这个注解,这就SpringBoot 的核心配置, 它可以帮我们自动装配好所有的依赖。

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

点进去这个注解:

还有三个核心的注解:

@SpringBootConfiguration

这个注解见名知意,就是SpringBoot 的配置

这个注解上还有一个注解: @Configuration, 我们点进去看一下

@Component 实际上就是一个组件。

@EnableAutoConfiguration

以前我们需要自己配置的东西,而现在SpringBoot可以自动帮我们配置 ;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能,这样自动配置才能生效;

这个注解中最重要的是导入的AutoConfigurationimportSelector这个类,我们点进去看看。

先说@import:

@import

Spring底层注解@import , 给容器中导入一个组件

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@documented
public @interface import {
    Class[] value();
}

@import(AutoConfigurationimportSelector.class)

给容器导入组件 ;

而这个注解也是一个派生注解,其中的关键功能由@import提供,其导入的AutoConfigurationimportSelector的selectimports()方法通过SpringFactoriesLoader.loadFactoryNames()扫描所有具有meta-INF/spring.factories的jar包。spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。

AutoConfigurationimportSelector :自动配置导入选择器,那么它会导入哪些组件的选择器呢?我们点击去这个类看源码:

其中有这样一个方法:

protected ListgetCandidateConfigurations(Annotationmetadata metadata, AnnotationAttributes attributes) {
    //这里的getSpringFactoriesLoaderFactoryClass()方法
    //返回的就是我们最开始看的启动自动导入配置文件的注解类;EnableAutoConfiguration
    List configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
    Assert.notEmpty(configurations, "No auto configuration classes found in meta-INF/spring.factories. If you are using a custom packaging, make sure that file is correct.");
    return configurations;
}
 

这个方法又调用了SpringFactoriesLoader 类的静态方法!我们进入SpringFactoriesLoader类loadFactoryNames() 方法

 public static List loadFactoryNames(Class factoryType, @Nullable ClassLoader classLoader) {
        ClassLoader classLoaderToUse = classLoader;
        if (classLoader == null) {
            classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
        }
​
        String factoryTypeName = factoryType.getName();
        return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    }

我们继续点击查看 loadSpringFactories 方法

private static Map> loadSpringFactories(ClassLoader classLoader) {
        Map> result = (Map)cache.get(classLoader);
    // 先从缓存中拿
        if (result != null) {
            return result;
        } else {
            // 如果缓存中拿不到,则重新导入
            HashMap result = new HashMap();
            try {
                // 读取配置,去获取一个资源 "meta-INF/spring.factories"
                Enumeration urls = classLoader.getResources("meta-INF/spring.factories");
                // 遍历这些配置,将其转换未Properties
                while(urls.hasMoreElements()) {
                    URL url = (URL)urls.nextElement();
                    UrlResource resource = new UrlResource(url);
                    Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                    Iterator var6 = properties.entrySet().iterator();
​
                    while(var6.hasNext()) {
                        Entry entry = (Entry)var6.next();
                        String factoryTypeName = ((String)entry.getKey()).trim();
                        String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue());
                        String[] var10 = factoryImplementationNames;
                        int var11 = factoryImplementationNames.length;
​
                        for(int var12 = 0; var12 < var11; ++var12) {
                            String factoryImplementationName = var10[var12];
                            ((List)result.computeIfAbsent(factoryTypeName, (key) -> {
                                return new ArrayList();
                            })).add(factoryImplementationName.trim());
                        }
                    }
                }
​
                result.replaceAll((factoryType, implementations) -> {
                    return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
                });
                cache.put(classLoader, result);
                return result;
            } catch (IOException var14) {
                throw new IllegalArgumentException("Unable to load factories from location [meta-INF/spring.factories]", var14);
            }
        }
    }

资源是从spring.factories读取的,我们全局搜索这个文件

看到了很多自动配置的文件;这就是自动配置根源所在! 这个spring.factories文件也是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔,如下图所示

WebMvcAutoConfiguration

可以看到这些一个个的都是JavaConfig配置类,而且都注入了一些Bean,可以找一些自己认识的类,看着熟悉一下!

所以,自动配置真正实现是从classpath中搜寻所有的meta-INF/spring.factories配置文件 ,并将其中对应的 org.springframework.boot.autoconfigure. 包下的配置项,通过反射实例化为对应标注了 @Configuration的JavaConfig形式的IOC容器配置类 , 然后将这些都汇总成为一个实例并加载到IOC容器中。

springboot所有的自动配置都是在启动的时候扫描并加载,扫描了spring.properties配置文件,所有的自动配置类都在这里面,但是不定生效,因为要判断条件是否成立,只要导入了对应的start,就有对应的启动器,有了启动器我们自动装配就会生效,然后就配置成功

步骤:

SpringBoot在启动的时候从类路径下的meta-INF/spring.factories中获取EnableAutoConfiguration指定的值 将这些值作为自动配置类导入容器 , 自动配置类就生效 , 帮我们进行自动配置工作;

以前需要我们配置的文件,springboot帮我们配置了!

整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;

整个J2EE的整体解决方案和自动配置都在springboot-autoconfigure的jar包中;

它会给容器中导入非常多的自动配置类 (xxxAutoConfiguration)@Bean, 就是给容器中导入这个场景需要的所有组件 , 并配置好这些组件 @Configuration;

有了自动配置类 , 免去了我们手动编写配置注入功能组件等的工作

SpringApplication.run分析

分析该方法主要分两部分,一部分是SpringApplication的实例化,二是run方法的执行;

SpringApplication

这个类主要做了以下四件事情:

1、推断应用的类型是普通的项目还是Web项目

2、查找并加载所有可用初始化器 , 设置到initializers属性中

3、找出所有的应用程序监听器,设置到listeners属性中

4、推断并设置main方法的定义类,找到运行的主类

查看构造器:

public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
    // ......
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    this.setInitializers(this.getSpringFactoriesInstances();
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = this.deduceMainApplicationClass();
}

关于springboot,谈谈你的理解:

springboot的自动装配 run(): ①判断当前项目是普通项目还是web项目 ②推断并设置main方法的定义类,找到运行的主类 ③run方法里面有一些监听器,这些监听器是全局存在的,它的作用是获取上下文处理一些bean,所有的bean无论是加载还是生产初始化多存在。

4, Yaml

YAML是 "YAML Ain't a Markup Language" (YAML不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种标记语言)

这种语言以数据作为中心,而不是以标记语言为重点!

以前的配置文件,大多数都是使用xml来配置;比如一个简单的端口配置,我们来对比下yaml和xml

传统xml配置:


    8081

yaml配置:

server:
  prot: 8080
基础语法

说明:语法要求严格!

1、空格不能省略

2、以缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的。

3、属性和值的大小写都是十分敏感的。

# 普通的键值对
# 格式: key: value 空格不能省略
​
# 我们在这里配置的值可以注入到Java对象中, 可以直接给实体类赋值, 这就是yaml的强大之处!
​
name: zyd
​
# 对象
student:
  name: zyd
  age: 18
​
# 行内对象
student2: { name: zyd,age: 18 }
​
# 数组
pets:
  - cat
  - og
  - pig
​
# 数组的行内语法
studentList: [ zyd, djy, cmy ]
​
Yaml属性配置注入

使用@ConfigurationProperties(prefix = ”对象名称“),可以注入属性到实体类中,前提就是实体类的属性名和Yaml对象的属性名是一致的!

@Data
@Component
@ConfigurationProperties(prefix = "person") // 使用yaml 注入到实体类中,前提是实体类的属性和yaml对象的属性名是对应的!
public class Person {
    private String name;
    private String age;
    private String school;
    private Dog dog;
    private Map map;
    private List list;
} 

YAML配置文件中配置对象。

person:
  name: zyd${random.uuid}
  age: 18-${random.int}
  school: ${person.age:other}_TUST # 如果有person这个属性,则拿到, 如果没有则使用:后面的值
  dog:
    name: zyj
    age: 10
    host: zyd
​
  map:
    contry: CHINA
​
  list: [ code, eat, sleep ]

测试类:

 @Autowired
    private Person person;
​
    @Test
    void contextLoads() {
//        System.out.println(dog.toString());
        System.out.println(person.toString());
    }
5, 多环境切换

我们日常开发时,用到的环境是开发环境。部署到服务器上是生产环境,那么这两个环境的配置属性(如路径。。。)一定是不同的, SpringBoot 提供了多环境配置,我们指定哪个环境就可以使用哪个环境的配置。

​
#  激活的环境配置
spring:
  profiles:
    active: dev
​
---
server:
  port: 8083
spring:
  profiles: dev
​
---
server:
  port: 8084
spring:
  profiles: prod  #配置环境的名称
​
6, 自动配置原理加深

在SpringFactories中的依赖项,我们点开一个配置CodecsAutoConfiguration。

//表示这是一个配置类,和以前编写的配置文件一样,也可以给容器中添加组件;
@Configuration 

//启动指定类的ConfigurationProperties功能;
  //进入这个HttpProperties查看,将配置文件中对应的值和HttpProperties绑定起来;
  //并把HttpProperties加入到ioc容器中
@EnableConfigurationProperties({HttpProperties.class}) 

//Spring底层@Conditional注解
//根据不同的条件判断,如果满足指定的条件,整个配置类里面的配置就会生效;
//这里的意思就是判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnWebApplication(
    type = Type.SERVLET
)

//判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;
@ConditionalOnClass({CharacterEncodingFilter.class})

//判断配置文件中是否存在某个配置:spring.http.encoding.enabled;
  //如果不存在,判断也是成立的
  //即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
@ConditionalOnProperty(
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)

public class HttpEncodingAutoConfiguration {
    //他已经和SpringBoot的配置文件映射了
    private final Encoding properties;
    //只有一个有参构造器的情况下,参数的值就会从容器中拿
    public HttpEncodingAutoConfiguration(HttpProperties properties) {
        this.properties = properties.getEncoding();
    }
    
    //给容器中添加一个组件,这个组件的某些值需要从properties中获取
    @Bean
    @ConditionalOnMissingBean //判断容器没有这个组件?
    public CharacterEncodingFilter characterEncodingFilter() {
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
        return filter;
    }
    //。。。。。。。
}

关于这个注解@EnableConfigurationProperties(),将传入的类加载成properties添加到IOC容器中, 我们点进去看一下ServerProperties。

@ConfigurationProperties 正是从yaml配置文件中拿出对应的配置。

我们可以配置SpringBoot 的yaml文件来配置这些属性。

7, 静态资源处理原理

我们在做web开发时,肯定会设计到很多静态资源的,这里我们看一下SpringBoot是怎样处理静态资源的。

在SpringFactories,点开WebMvcAutoConfiguration。

加载资源的方法

		@Override
		public void addResourceHandlers(ResourceHandlerRegistry registry) {
			// 首先判断是否适配
            if (!this.resourceProperties.isAddMappings()) {
				logger.debug("Default resource handling disabled");
				return;
			}
            // 加载资源 /webjars/** 的资源会被加载
			addResourceHandler(registry, "/webjars/**", "classpath:/meta-INF/resources/webjars/");
			// staticPathPattern  下的资源        
			addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
				registration.addResourceLocations(this.resourceProperties.getStaticLocations());
				if (this.servletContext != null) {
					ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
					registration.addResourceLocations(resource);
				}
			});
		}

这个方法使用了EnableConfigurationProperties注解,说明这个注解自动帮我们导入了一些properties。

@SuppressWarnings("deprecation")
	@Configuration(proxyBeanMethods = false)
	@import(EnableWebMvcConfiguration.class)
	@EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })
	@Order(0)
	public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {

		private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);

		private final Resources resourceProperties;

		private final WebMvcProperties mvcProperties;

		private final ListableBeanFactory beanFactory;

		private final ObjectProvider messageConvertersProvider;

		private final ObjectProvider dispatcherServletPath;

		private final ObjectProvider> servletRegistrations;

		private final ResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizer;

		private ServletContext servletContext;

		public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties,
				ListableBeanFactory beanFactory, ObjectProvider messageConvertersProvider,
				ObjectProvider resourceHandlerRegistrationCustomizerProvider,
				ObjectProvider dispatcherServletPath,
				ObjectProvider> servletRegistrations) {
			this.resourceProperties = webProperties.getResources();
			this.mvcProperties = mvcProperties;
			this.beanFactory = beanFactory;
			this.messageConvertersProvider = messageConvertersProvider;
			this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
			this.dispatcherServletPath = dispatcherServletPath;
			this.servletRegistrations = servletRegistrations;
			this.mvcProperties.checkConfiguration();
		}

其中@EnableConfigurationProperties帮我们将配置加载成properties,点开WebProperties。

在springboot,我们可以使用一下方式处理静态资源 webjars localhost:8080/webjars/ public , static , /** , resources localhost:8080/ 优先级 : resources > static > public

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号