Day44——SpringBoot学习笔记part2

SpringBoot学习part2

微服务

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

将一个个微服务想象成一个个的业务,一个模块一个模块的

  • 单体应用架构(all in one)是指,我们将一个应用的中的所有应用服务都封装在一个应用中。无论是ERP、CRM或是其他什么系统,你都把数据库访问,web访问,等等各个功能放到一个war包内。

    • 缺点是,哪怕我要修改一个非常小的地方,我都需要停掉整个服务,重新打包、部署这个应用war包
  • 所谓微服务架构,就是打破之前all in one的架构方式,把每个功能元素独立出来。把独立出来的功能元素的动态组合,需要的功能元素才去拿来组合,需要多一些时可以整合多个功能元素。所以微服务架构是对功能元素进行复制,而没有对整个应用进行复制。

  • 比如一个电商系统,查缓存、连数据库、浏览页面、结账、支付等服务都是一个个独立的功能服务,都被微化了,它们作为一个个微服务共同构建了一个庞大的系统。

  • 但是这种庞大的系统架构给部署和运维带来很大的难度。于是,spring为我们带来了构建大型分布式微服务的全套、全程产品

springboot原理

1、pom.xml文件

  • < parent>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.5.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

点入spring-boot-starter-parent—>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.2.5.RELEASE</version>
    <relativePath>../../spring-boot-dependencies</relativePath>
</parent>

点入spring-boot-dependencies—>核心依赖,在父工程中,所以引入一些springboot依赖时,不需要指定的版本

  • 启动器
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

上面的含义就是在web场景下启动SpringBoot,自动就装配web环境所有依赖

Springboot会将所有的功能场景,变成一个个的启动器,使用什么功能,就找到对应的starter

2、主程序

@SpringBootApplication
public class Spbootdemo2Application {

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

}

表面解释:@SpringBootApplication标注这个类是一个SpringBoot的应用:启动类下的所有资源被导入;调用SpringApplication的静态方法run将springboot应用启动。

  • 注解:
//元注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited

//重点是:
@SpringBootConfiguration  //springboot的配置
	@Configuration        //spring配置类
		@Component        //说明这也是个spring的组件

@EnableAutoConfiguration  //自动配置
	@AutoConfigurationPackage   //自动配置包
		@Import(AutoConfigurationPackages.Registrar.class)//自动配置包,注册
	@Import(AutoConfigurationImportSelector.class)	//自动配置导入选择器	
		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);//获取所有的配置		

获取候选配置的方法:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
                                                                         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;
}

自动配置的核心文件

META-INF/spring.factories

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cagAuv12-1583811271811)(springboot2.assets/1583652747341.png)]

所有的资源加载到配置类里

Properties properties = PropertiesLoaderUtils.loadProperties(resource);

springboot所有的自动配置都在启动类中扫描、加载,加载在spring.factories,所有的自动配置类都在这里,要判断条件是否成立,只有导入了对应的start,有了对应的启动器,自动装配就生效

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NJa54Xqb-1583811271812)(springboot2.assets/1583654645368.png)]

  • run方法
//参数一:应用入口的类   参数二:命令行参数
SpringApplication.run(Spbootdemo2Application.class, args);

加载主类然后加载配置类以及其他组件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xsf5mkvX-1583811271813)(springboot2.assets/1583655643515.png)]

yaml配置文件

配置文件作用:修改SpringBoot自动装配的默认值,SpringBoot在底层都给我们自动配置好了;

yaml标记语言

基础语法:

k:(空格) v 

来表示一对键值对(空格不能省略)。以空格的缩进来控制层级关系,只要是左边对齐的一列数据都是同一个层级的。

值的写法:

字面量:普通的值  [数字,布尔值,字符串]
字面量直接写在后面就可以,字符串默认不用加上双引号或者单引号;

“”双引号,不会转义字符串里面的特殊字符,特殊字符会作为本身想表示的意思;

比如:name: “xing \n ming"   输出: xing  换行   ming

'' 单引号,会转义特殊字符,特殊字符最终会变成和普通字符一样输出

比如:name: ‘xing \n ming’   输出 : xing \n ming

对象、Map(键值对)

k: 
    v1:
    v2:

数组( List、set )

用 - 值表示数组中的一个元素,比如:

XYZ:
 - X
 - Y
 - Z
注入配置文件

yaml可以直接给实体类赋值

测试:

<!--导入配置文件处理器,配置文件进行绑定就会有提示-->
<dependency>    
    <groupId>org.springframework.boot</groupId
    <artifactId>spring-boot-configuration-processor</artifactId>    
    <optional>true</optional>
</dependency>

编写Person,Dog类

@Component //注册bean
@ConfigurationProperties(prefix = "person")//把Person类与配置文件绑定

public class Person {

    private String name;
    private Integer age;
    private Boolean happy;
    private Date birth;
    private Map<String,Object> maps;
    private List<Object> lists;
    private Dog dog;

    //get,set方法
    //toString方法
    
}
@Component //注册bean
public class Dog {
    private String name;
    private Integer age;
    
    //get、set方法
    //toString()方法  
}

编写yaml配置文件

person:
    name: 小名
    age: 6
    happy: true
    birth: 2020/02/02
    maps: {k1: v1,k2: v2}
    lists:
      - code
      - play
      - music
    dog:
      name: 旺旺
      age: 2

测试单元中进行测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootDemo03ApplicationTests {

    @Autowired
    Person person = new Person();

    @Test
    public void contextLoads() {
        System.out.println(person);
    }

}

控制台查看输出

tips:松散绑定,这个什么意思呢? 比如在yml中写的last-name,类中的属性lastName是一样的, - 后面跟着的字母默认是大写的。这就是松散绑定

JSR303数据校验

在Person类中使用 @validated来校验数据 ,如,在name属性上 只能支持Email格式

@Component //注册bean
@ConfigurationProperties(prefix = "person")
@Validated  //数据校验
public class Person {

    @Email //name必须是邮箱格式
    //还可自定义报错信息@Email(message="邮箱格式不对哦")
    private String name;
}

校验的源码位置:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D5AimkxD-1583811271814)(springboot2.assets/1583661407083.png)]

更多的注解如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-viPw24p7-1583811271814)(springboot2.assets/1583661150444.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xBMqdTXC-1583811271816)(springboot2.assets/1583661168307.png)]

多文档环境切换

配置文件加载位置,默认配置位置有4个,其中file指的项目路径

springboot 启动会扫描以下位置的application.properties或application.yml文件作为Spring boot的默认配置文件

  • file:./config/
  • file:./
  • classpath:/config/
  • classpath:/

优先级1:项目路径下的config文件夹配置文件

优先级2:项目路径下配置文件

优先级3:资源路径下的config文件夹配置文件

优先级4:资源路径下配置文件

Springboot的多环境配置,选择激活哪一个配置文件

可建立application.properties(默认)、application-dev.properties(开发)、application-test.properties(测试)

# application.properties中
# Springboot的多环境配置,选择激活哪一个配置文件
spring.profiles.active=dev

测试:

# application-dev.properties
server.port=8081
# application-test.properties
server.port=8082

当active=dev时,就会从8081端口启动项目。

用yml实现

建立application.yml,多环境使用---分隔

server:
  port: 8081

---
server:
  port: 8082
spring:
  profiles: dev

---
server:
    port: 8083
spring:
  profiles: test

如何激活?

server:
  port: 8081
spring:
  profiles:
    active: dev

自动装配再学习

  • 配置文件到底怎么写?

配置文件中都存在一个规律,

@xxxAutoConfiguration ---- @xxxProperties ---- 自己的配置文件绑定

@xxxAutoConfiguration 存在默认值,如何改变?

@xxxProperties和自己的配置文件绑定后就可以使用自定义的配置了

如:配置Http的编码

在META-INF/spring.factories中

org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration,\

HttpEncodingAutoConfiguration类

//表示这是一个配置类,会被Spring接管配置
@Configuration(proxyBeanMethods = false)
//自动配置属性,HttpProperties 代码如下面
@EnableConfigurationProperties(HttpProperties.class)

//@ConditionalOnXX,spring的底层注解,根据不同的条件,来判断当前配置或类是否生效
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {

	private final HttpProperties.Encoding properties;

	public HttpEncodingAutoConfiguration(HttpProperties properties) {
		this.properties = properties.getEncoding();
	}

	@Bean
	@ConditionalOnMissingBean
	public CharacterEncodingFilter characterEncodingFilter() {
		CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
		filter.setEncoding(this.properties.getCharset().name());
		filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
		filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
		return filter;
	}

	@Bean
	public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
		return new LocaleCharsetMappingsCustomizer(this.properties);
	}

	private static class LocaleCharsetMappingsCustomizer
			implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {

		private final HttpProperties.Encoding properties;

		LocaleCharsetMappingsCustomizer(HttpProperties.Encoding properties) {
			this.properties = properties;
		}

		@Override
		public void customize(ConfigurableServletWebServerFactory factory) {
			if (this.properties.getMapping() != null) {
				factory.setLocaleCharsetMappings(this.properties.getMapping());
			}
		}

		@Override
		public int getOrder() {
			return 0;
		}
	}
}

HttpProperties类

@ConfigurationProperties(prefix = "spring.http")
public class HttpProperties {

	/**
	 * Whether logging of (potentially sensitive) request details at DEBUG and TRACE level
	 * is allowed.
	 */
	private boolean logRequestDetails;

	/**
	 * HTTP encoding properties.
	 */
	private final Encoding encoding = new Encoding();

	public boolean isLogRequestDetails() {
		return this.logRequestDetails;
	}

	public void setLogRequestDetails(boolean logRequestDetails) {
		this.logRequestDetails = logRequestDetails;
	}

	public Encoding getEncoding() {
		return this.encoding;
	}

	/**
	 * Configuration properties for http encoding.
	 */
	public static class Encoding {

		public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;

		/**
		 * Charset of HTTP requests and responses. Added to the "Content-Type" header if
		 * not set explicitly.
		 */
		private Charset charset = DEFAULT_CHARSET;

		/**
		 * Whether to force the encoding to the configured charset on HTTP requests and
		 * responses.
		 */
		private Boolean force;

		/**
		 * Whether to force the encoding to the configured charset on HTTP requests.
		 * Defaults to true when "force" has not been specified.
		 */
		private Boolean forceRequest;

		/**
		 * Whether to force the encoding to the configured charset on HTTP responses.
		 */
		private Boolean forceResponse;

		/**
		 * Locale in which to encode mapping.
		 */
		private Map<Locale, Charset> mapping;

		public Charset getCharset() {
			return this.charset;
		}

		public void setCharset(Charset charset) {
			this.charset = charset;
		}

		public boolean isForce() {
			return Boolean.TRUE.equals(this.force);
		}

		public void setForce(boolean force) {
			this.force = force;
		}

		public boolean isForceRequest() {
			return Boolean.TRUE.equals(this.forceRequest);
		}

		public void setForceRequest(boolean forceRequest) {
			this.forceRequest = forceRequest;
		}

		public boolean isForceResponse() {
			return Boolean.TRUE.equals(this.forceResponse);
		}

		public void setForceResponse(boolean forceResponse) {
			this.forceResponse = forceResponse;
		}

		public Map<Locale, Charset> getMapping() {
			return this.mapping;
		}

		public void setMapping(Map<Locale, Charset> mapping) {
			this.mapping = mapping;
		}

		public boolean shouldForce(Type type) {
			Boolean force = (type != Type.REQUEST) ? this.forceResponse : this.forceRequest;
			if (force == null) {
				force = this.force;
			}
			if (force == null) {
				force = (type == Type.REQUEST);
			}
			return force;
		}

		public enum Type {
			REQUEST, RESPONSE
		}
	}
}

看到HttpProperties的注解上有perfix=“spring.http”

此时,我们对应配置文件可以写

# 就会提示出所能写的配置,对应HttpProperties类中的属性
spring.http.

当这个配置类生效,这个配置类就会给容器中添加各种组件,这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的,所以这样就可以使配置文件动态修改springboot 的一些东西。

知识点:

  • Springboot启动会加载大量的自动配置类
  • 我们看我们需要的功能有没有在springboot默认写好的自动配置类当中
  • 再来看这个自动配置类中到底配置了那些组件,只要我们要用的组件存在,我们就不会需要手动配置了
  • 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性,我们只需要在配置文件中指定这些属性的值即可
  • XX AutoConfiguration:自动配置类,给容器中添加组件
  • XX Properties:封装配置文件中相关属性,如何修改,springboot配置文件(yml,properties,)

查看项目中哪些自动配置类生效,可以在配置文件中使用下面的代码:

debug=true

这样启动项目后,在控制台打印输出生效配置

在这里插入图片描述

Web开发准备

静态资源导入
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    //
    if (!this.resourceProperties.isAddMappings()) {
        logger.debug("Default resource handling disabled");
        return;
    }
    Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
    CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
    if (!registry.hasMappingForPattern("/webjars/**")) {
        customizeResourceHandlerRegistration(registry.addResourceHandler("/webjars/**")
                                             .addResourceLocations("classpath:/META-INF/resources/webjars/")
                                             .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
    }
    String staticPathPattern = this.mvcProperties.getStaticPathPattern();
    if (!registry.hasMappingForPattern(staticPathPattern)) {
        customizeResourceHandlerRegistration(registry.addResourceHandler(staticPathPattern)
                                             .addResourceLocations(getResourceLocations(this.resourceProperties.getStaticLocations()))
                                             .setCachePeriod(getSeconds(cachePeriod)).setCacheControl(cacheControl));
    }
}
  • 第一种拿到静态资源的方法,是webjars
    • 可以用maven的方式,如在webjars网站上取得< dependency>XXX< /dependency>文件放入pom.xml中
    • 启动项目,在路径输入localhost:8080/webjars/**(比如jquery/3.4.1/jquery.js)就可以拿到web资源
  • 第二种

在WebMvcProperties类中

/**
	 * Path pattern used for static resources.
	 */
private String staticPathPattern = "/**";
//当在localhost:8080/**--->会到下面的4个路径去找

在ResourceProperties类中

private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" };

/**
	 * Locations of static resources. Defaults to classpath:[/META-INF/resources/,
	 * /resources/, /static/, /public/].优先级如排序顺序!
	 */
  • 还可以自定义路径

配置文件中

spring.mvc.static-path-pattern=/lala/
首页定制

WebMvcConfiguration类中

@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
                                                           FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
    WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
        new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
        this.mvcProperties.getStaticPathPattern());
    welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
    return welcomePageHandlerMapping;
}

private Optional<Resource> getWelcomePage() {
    String[] locations = getResourceLocations(this.resourceProperties.getStaticLocations());
    return Arrays.stream(locations).map(this::getIndexHtml).filter(this::isReadable).findFirst();
}

private Resource getIndexHtml(String location) {
    //在静态资源目录下,找到index.html就会映射到首页
    return this.resourceLoader.getResource(location + "index.html");
}

private boolean isReadable(Resource resource) {
    try {
        return resource.exists() && (resource.getURL() != null);
    }
    catch (Exception ex) {
        return false;
    }
}

在templates目录下的所有页面,只能通过controller来跳转

Thymeleaf模板引擎

模板引擎作用:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GjnFeMGH-1583811271818)(springboot2.assets/1583809213638.png)]

使用:在pom.xml中

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

thymeleaf所有模板引擎写在templates目录下

ThymeleafProperties类:

@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {

	private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;

	public static final String DEFAULT_PREFIX = "classpath:/templates/";

	public static final String DEFAULT_SUFFIX = ".html";

    .....
}

使用:

controller中:

@Controller
public class Controller {

    @RequestMapping("/home")
    public String list(Model model){
        model.addAttribute("msg","hello,thymeleaf");
        return "home";
    }
}

在templates下建立home.html

<!DOCTYPE html> 
<html xmlns:th="http://www.thymeleaf.org">
    <head> 
        <title>Good Thymes Virtual Grocery</title> 
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
    </head> 
    <body> 
        <p th:text=${msg}"></p>
        <!--th: 元素名 ;就是使用thymeleaf模板,所有html元素可以被thymeleaf接管-->
    </body> 
</html>

简单的一些表达式:

  • Variable Expressions: ${…}

  • Selection Variable Expressions: *{…}

  • Message Expressions: #{…}

  • Link URL Expressions: @{…}

  • Fragment Expressions: ~{…}

有一些二元三元表达式:

  • If-then: (if) ? (then)
  • If-then-else: (if) ? (then) : (else)
  • Default: (value) ?: (defaultvalue)

语法:

model.addAttribute(“msg”,“hello,thymeleaf”);
return “home”;
}
}


在templates下建立home.html

```html
<!DOCTYPE html> 
<html xmlns:th="http://www.thymeleaf.org">
    <head> 
        <title>Good Thymes Virtual Grocery</title> 
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> 
    </head> 
    <body> 
        <p th:text=${msg}"></p>
        <!--th: 元素名 ;就是使用thymeleaf模板,所有html元素可以被thymeleaf接管-->
    </body> 
</html>

简单的一些表达式:

  • Variable Expressions: ${…}

  • Selection Variable Expressions: *{…}

  • Message Expressions: #{…}

  • Link URL Expressions: @{…}

  • Fragment Expressions: ~{…}

有一些二元三元表达式:

  • If-then: (if) ? (then)
  • If-then-else: (if) ? (then) : (else)
  • Default: (value) ?: (defaultvalue)

语法:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pJhnfB3C-1583811271819)(springboot2.assets/1583810724279.png)]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值