springBoot

springBoot构建

parent

spring boot 继承了spring-boot-dependencies 定义了很多包的版本,在使用的时候无需指定包版本,直接使用,免去了人工依赖导致版本冲突,依赖的管理完全取决于spring boot 的大版本,继承parent的形式也可以采用引用依赖的形式效果

starter

spring boot 中常见的项目名称,定义了当前项目使用的所有依赖坐标,以达到减少配置的目的

引导类

@SpringBootApplication
public class ExceltoolApplication {
    public static void main(String[] args) {
        SpringApplication.run(ExceltoolApplication.class, args); // 返回值就是一个启动spring容器
    }

}
@SpringBootApplication // 默认扫描包为引导类所在的包及其子包放入容器@CompoentScan规则

内置tomcat

spring-boot-starter-tomcat ===>内嵌了tomcat核心 tocat-embed-core 
运行的时候封装成tomcat对象,放到spring容器中
可以指定其他服务器 jetty weblogic等 在web工程中排除tomcat 依赖

获取bean的方式

获取容器
ApplicationContext ioc = new ClassPathXmlApplicationContext("application.xml")
1、根据id获取
ioc.getBean("helloword")
2、根据类型获取
ioc.getBean(Helloword.class)
3、根据id和类型获取
ioc.getBean("helloword",Helloword.class)
4、我们还是可以通过接口Person来获取到Student的bean。也就是说在IOC容器中配置了一个bean后,我们是可以通过它所继承的父类或所实现的接口来获取

springBoot配置

配置文件加载顺序和级别

application.properties >application.yml >application.yaml

1级:file :config/application.yml // 最高
2级:file :application.yml
3级:classpath: config/application.yml
4级:classpath: application.yml  // 最低

读取配置文件

baseDir: c:\user
tempDir:${baseDir}\temp
datasource.driver= com.mysql.jdbc.Driver
datasource.url = jdbc:mysql://localhost/springboot
datasource.username = root
datasource.password = 123456

@Value("${key: 默认值}")

@Value("${tempDir}")   
private String tempDir;

 Environment 对象

@Autowired
private Environment env; //所有属性都在这个对象中

env.getProperty("temDir")

 @ConfigurationProperties("datasource")

// 首先得是一个spring管控的bean
@Compoent
@ConfigurationProperties("datasource")   // 配置前缀
pulic class MyDatasource{
    private String dirver;
    private String url;
    private String username;
    private String password;
}

 多环境开发

spring:
	profiles:
		active: pro  // 当前激活环境
---
server:
	port: 80
spring:
	config:
		activate:
			on-profile:pro 
---
server:
	port: 81
spring:
	config:
		activate:
			on-profile:dev

 上述多环境在一个配置文件中,可以分成三个多环境配置文件application.yml(主配置文件), application-pro.yml,application-dev.yml

#主配置文件 指定环境
spring:
	profiles:
		active: pro
#application-pro.yml文件
server:
	port: 80
spring:
	config:
		activate:
			on-profile:pro 
#application-dev.yml文件
server:
	port: 81
spring:
	config:
		activate:
			on-profile:dev

 多环境开发包含文件使用group(include 2.4以前版本)属性设置配置文件分组,便于线上管理注意:如果是properties 只支持多文件版本,不支持---单一文件配置

 maven profille的级别大于配置文件profile

<!--pom-->
<profiles>
	<profile>
    	<id>env_dev</id>
        <properties>
            <profile.active>dev</profile.active>
        </properties>
        <activation>
            <!--默认启动dev-->
        	<actoveByDefault>true</actoveByDefault>  
        </activation>
    </profile>
    	<profile>
    	<id>env_pro</id>
        <properties>
            <profile.active>pro</profile.active>
        </properties>
    </profile>
</profiles>

yml 读取pom环境(读取maven配置属性值 @..@

spring:
	profiles:
		active: @profile.active@ # 读取maven配置属性值 @..@
		group:
			"dev": pro,aa
			"pro": dev,bb

 配置高级

 @ConfigurationProperties可以为第三方bean绑定属性

@SpringBootApplication
@EnableConfigurationProperties // 可以将使用@ConfigurationProperties注解对应的类加入spring容器
public class SpringBootDemo{
    
    @Bean
    @ConfigurationProperties(perfix = "datasource")
    public DruidDataSource datasource(){
        return new DruidDataSource();
    }
}
// @EnableConfigurationProperties 与@Compoent 不能同时使用

 解除使用@ConfigurationProperties注释警告

Spring Boot Configuration Annotation Processor not configured

<dependency>
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
</dependency>

@ConfigurationProperties松散绑定

servers:
	ip_adress:192.168.0.143
@ConfigurationProperties("servers")
public class Test(){
    private String ipAdress; // 能够匹配配置中的ip-adress  常量、中划线模式、下划线等 只有@ConfigurationProperties注解能用,@Value就不能用
}

常用计量单位

servers:
	serverTimeOut:3  #默认s
	data-size: 10
@ConfigurationProperties("servers")
public class Test(){
    @DurationUnit(ChronoUnit.MINUTES)  //支持多种形式
    private Duration serverTimeOut;   //JDK8提供的计量单位
    @DataSizeUnit(DataUnit.Bytes)
    private DataSize datasize; // 容量大小
}

数据校验JSR303  

<!--导入校验规范-->
<dependency>
	<groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
</dependency>
<!--添加校验器实现-->
<dependency>
	<groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
</dependency>
@ConfigurationProperties("servers")
// 开启对当前bean属性注入校验
@Validated 
public class Test(){
    @DurationUnit(ChronoUnit.MINUTES)  
    private Duration serverTimeOut;  
    // 设置校验规则
    @Max(value=8888,message="最大值不能超过8888")
    @DataSizeUnit(DataUnit.Bytes)
    private DataSize datasize; 
}

配置需注意进制转换

dataSource:
	password: 0127 # 读到的属性为 8进制 为87 方式为 "0127"

springBoot 开发

异常处理器

 在表现层 controller处理异常即可,所有异常都会抛到表现层

@RestControllerAdvice  // springMVC异常处理器
public class ProjectExceptionAdvice{
    // 拦截所有异常信息
    @ExceptionHandler(Exception.class)
    public Result doException(Exception ex){
        // 记录日志
        ex.printStackTrace();
        return new Result(500,"服务器故障")  // 返回统一结果集
    }
}

临时属性设置

java -jar springboot.jar --server.port = 80  

多个属性之间用空格连接(命令行参数)  --属性名 = 值  命令行属性 > 配置属性 

 日志

public class XxxController{
    // 日志 导包 导入日志门面 slf4j
    private static final Logger log = LoggerFactory.getLogger(XxxController.class);
    
    public String getXxx(){
        // 级别由低到高
        log.debug("debug...");
        log.info("info...");
        log.warn("warn...");
        log.error("error...");  
    }
}
// 默认系统日志为info级别 
调整日志级别配置 debug:true
logging.level.root = info // 项目路径下的日志级别
// 注解形式日志
基于lombok提供的@Slf4j注解为类快速添加日志对象    

 日志输出格式

时间 级别PID---[所属线程] 当前记录位置(包名过长会简化包名等): 日志信息

设置日志输出格式

# %p代表级别 
#%5n 占5个位置 换行
#%clr显示颜色 
#%16t 显示线程
#%40c 显示类型  %-40.40c  -40左对齐 40.40 包名.类名
#%m   显示消息
logging:
	pattern:
		#console: "%d - %m %n"
		#console: "%d %clr(%5p) --- [%16t] %-40.40c :%m %5n" 

日志输出到文件  

logging:
	file:
		name: server.log  # 位置在项目同级目录
	logback:
    	rollingpolicy:    #设置滚动日志
    		max-file-size :4kB  #最大文件大小 超过大小在来一个新文件
    		file-name-pattern:server.%d{yyyy-mm-dd}.%i.log #文件名 %d 时间 %i index 0开始  

单独日志配置文件 src/main/resources/logback-spring.xml

<?xml version="1.0" encoding="utf-8" ?>
<!-- 从高到地低 OFF 、 FATAL 、 ERROR 、 WARN 、 INFO 、 DEBUG 、 TRACE 、 ALL -->
<!-- 日志输出规则  根据当前ROOT 级别,日志输出时,级别高于root默认的级别时  会输出 -->
<!-- 以下  每个配置的 filter 是过滤掉输出文件里面,会出现高级别文件,依然出现低级别的日志信息,通过filter 过滤只记录本级别的日志-->

<!-- 属性描述 scan:性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,
默认单位是毫秒。当scan为true时,此属性生效。默认的时间间隔为1分钟。debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。 -->
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <!-- 定义日志文件 输入位置 -->
    <property name="logPath" value="./excel_log" />
    <!-- 日志最大的历史 30天 -->
    <property name="maxHistory" value="30"/>

    <appender name="consoleLog" class="ch.qos.logback.core.ConsoleAppender">
        <!-- layout代表输出格式 -->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger -%msg%n</pattern>
        </layout>
    </appender>


    <!-- 日志输出文件 -->
    <appender name="fileInfoLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger -%msg%n</pattern>
        </encoder>
        <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 RollingFileAppender-->
        <!-- 滚动策略,它根据时间来制定滚动策略.既负责滚动也负责触发滚动 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 输出路径 -->
            <fileNamePattern>${logPath}/info/%d.log</fileNamePattern>
            <!-- 可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件假设设置每个月滚动,且<maxHistory>是6,
            则只保存最近6个月的文件,删除之前的旧文件。注意,删除旧文件是,那些为了归档而创建的目录也会被删除-->
            <maxHistory>${maxHistory}</maxHistory>

        </rollingPolicy>
    </appender>

    <!-- 特殊记录Error日志 -->
    <appender name="fileErrorLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 只记录ERROR级别日志,添加范围过滤,可以将该类型的日志特殊记录到某个位置 -->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>ERROR</level>
        </filter>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger -%msg%n</pattern>
        </encoder>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${logPath}/error/%d.log</fileNamePattern>
            <maxHistory>60</maxHistory>
        </rollingPolicy>
    </appender>

    <!--定义日志输出级别-->
    <logger name="com.baomidou.mybatisplus" level="INFO" />
    <logger name="com.neuxa.egi.exceltool.controller" level="INFO"/>

    <root level="info">
        <!-- 引入控制台输出规则 -->
        <appender-ref ref="consoleLog" />
        <appender-ref ref="fileInfoLog" />
        <appender-ref ref="fileErrorLog" />
    </root>
</configuration>

热部署

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

注意:手动开启热部署 Ctrl+F9  重新构建 热部署不加载jar资源,只加载自身开发资源

自动启动热部署

  1. settings=>Complier => Build Project automatically【勾选】
  2. Ctrl +Alt+ Shift +/ =>Registry => complier.automake.allow.when.app.running【勾选】
  3. 规则:自动原则,当编译器失去焦点5s之后自动构建

热部署范围  

默认不触发重启的目录列表
    /META-INF/maven
    /META-INF/resources
    /resources
    /static
    /public
    /templates

// 设置不参与热部署的范围
spring.devtools.restart.exclude = static/**,public/**,config/application.yml 

关闭热部署

spring.devtools.restart.enable = false

测试

加载测试专用属性

@springBootTest(args ={"--test.arg = testValue"},properties = {"test.arg = testvalue1"})
@Import(MsgConfig.class) // 仅仅在局部测试生效
public class PropertiesTest{
    @Value("${test.arg}")
    private String msg;
    
    @Autoeired
    private String ttmsg;
    
    @Test
    void testArgs(){
        System.out.println(msg);
        System.out.println(ttmsg);
    }
}

 测试web环境虚拟调用

@springBootTest(WebEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) //指定随机端口
// 开启虚拟MVC调用
@AutoConfigureMockMVc
public class PropertiesTest{
    
    @Test
    void test(@Autowired MockMvc mvc) throws Exception{
        // 创建了一个虚拟请求 ,当前访问/books
       MockHttpServletRequestBuilder builder  = MockMvcRequestBuilders.get("/books")
       // 执行请求    
       ResultActions action =mvc.perform(builder)
       //设置执行状态匹配器
       StatusResultMatchers status = MockMvcResultMatchers.status();  
       // 设置预计成功状态 200
       ResultMatcher ok = status.isOk();
       // 添加预计值匹配
       action.addExpect(ok);
           
    }
}
// 测试web环境端口测试

数据库层测试事务回滚  

@springBootTest
@Transactional // 加上它标识事务不提交 springboot发现它是测试类,所以不提交事务
@Rollback(false) // 设置不回滚 提交事务
public class DaoTest{
    
}

数据层解决方案

sql解决方案(mysql sqlserver oracle)

spring boot 内嵌3种数据库 H2 HSQL Derby  
spring boot 内嵌3中数据源对象 
    HikariCP:默认内置数据源对象
    Tomcat提供的DataSource:HikariCP不可用的时候,且在web环境中将使用tomcat提供的数据源对象
    Commons DBCP: HikariCP不可用,Tomcat提供的DataSource也不可用,使用dbcp数据源 
通过数据源对象获取数据库链接        

spring:
	datasource:
		url:jdbc:mysql://localhost:3306/ssm?serverTimeZone=UTC
		hikari:
			driver-class-name:com.mysql.cj.jdbc.Driver
			username:root
			password:root
			maximun-pool-size:50
---
spring:
	datasource:
		url:jdbc:mysql://localhost:3306/ssm?serverTimeZone=UTC
		druid:
			driver-class-name:com.mysql.cj.jdbc.Driver
			username:root
			password:root
			maximun-pool-size:50

nosql解决方案(redis、mongo、es)  

整合redis

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
spring:
  redis:
    host: localhost
    port: 6379

 操作redis

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
 
@SpringBootTest
class Springboot16RedisApplicationTests {
	//用这个属性就能操作Redis
    @Autowired
    private RedisTemplate redisTemplate;
 
	//下面测试类运行的时候,一定要确保Redis是开启的状态
    @Test
    void set() {
     // String类型
     ValueOperations valueOperations = redisTemplate.opsForValue();
     valueOperations.set("age","41");  
    }
 
    @Test
    void get() {
        // 取值
        ValueOperations valueOperations = redisTemplate.opsForValue();
        Object age = valueOperations.get("age");   
        System.out.println(age);
    }
 
	//hash
    @Test
    void hSet() {
       HashOperations  ho = redisTemplate.opsForHash();
        // key是info   
        ho.put("info","a","aa");  
    }
 
    @Test
    void hGet() {
      //获取值  
      HashOperations ho = redisTemplate.opsForHash();
      Object p =  ho.get("info","a");
      System.out.println(p);
    }
 
}

发现问题,redisTemplate操作的行为,在命令行不同步,具体原因 RedisTemplate<k,V> 带有泛型,不给,默认以对象的方式操作的redis,可以使StringRedisTemplate方式操作redis  

import org.springframework.data.redis.core.ValueOperations;
 
@SpringBootTest
public class StringRedisTemplateTest {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;  
 
    @Test
    void get(){
        ValueOperations<String,String> ops = stringRedisTemplate.opsForValue();
        String name = ops.get("name");
        System.out.println(name);
    }
}

 jedis操作redis

<dependency>
  <groupId>redis.clients</groupId>
  <artifactId>jedis</artifactId>
</dependency>
spring:
  redis:
    host: localhost
    port: 6379
    client-name: jedis

运行之前的代码,一样的效果,jedis和lettuce 都是springboot的内部实现,外层不表现,默认使用lettuce,如果使用jedis,引入依赖,配置使用

整合mogodb  

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
spring:
  data:
    mongodb:
      uri: mongodb://localhost/test

 操作mogo

@SpringBootTest
class Springboot17MongodbApplicationTests {
 
    @Autowired
    private MongoTemplate mongoTemplate;
 
    @Test
    void save() {
        Book book = new Book();
        book.setId(111);
        book.setType("1");
        book.setDescription("perfect");
        mongoTemplate.save(book);
    }
    @Test
    void find(){
      List<Book> all =  mongoTemplate.findAll(Book.class);
      System.out.println(all);
    }

}

整合es 

 es 分布式全文检索,java语言编写,安装默认带一个高版本jdk,方便后续拓展,.kibana客户端操作连接es,根据关键字得到id,在通过id查到数据,称为倒排索引,分词器(ik存储数据),建立索引映射规则,加分词器,添加文档,_doc/1 都是以请求的方式添加

  • Lucene:底层的API,工具包
  • Solr:基于Lucene开发的企业级的搜索引擎产品
  • Elasticsearch:基于Lucene开发的企业级的搜索引擎产品
<!--低级别客户端引入方式-->
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
#第二种方法:Druid专用配置  推荐
spring:
  datasource:
    druid:
      driver-class-name: com.mysql.cj.jdbc.Driver
      url: jdbc:mysql://localhost:3306/user_db?serverTimezone=GMT
      username: root
      password: admin
  #低级别配置方式   
  elasticsearch:
    rest:
      uris: http://localhost:9200
<!--高级别引入推荐-->
<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
  // 手动开启客户端,不是springboot维护
   private RestHighLevelClient client;
    @Test
    void testCreateClient() throws IOException{
        HttpHost host = HttpHost.create("http://localhost:9200");
        RestClientBuilder builder = RestClient.builder(host);
        client = new RestHighLevelClient(builder);
        // 创建名称为books的索引
        CreateIndexRequest request = new CreateIndexRequest("books");
        client.indices().create(request,RequestOptions.DEFAULT)
        //  关闭客户端 
        client.close();
    }

 缓存(数据临时存储介质)

springboot 提供了缓存技术,还可以对其他缓存技术进行整合,统一接口,方便缓存技术的开发管理

Generic
JCache
EhCache
Hazelcast
Infinispan
Couchbase
Redis
Caffenine
Simple(默认 内存级)
memcached 不是springboot内置的

导入依赖  

<dependency>
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>
@SpringBootApplication
@EnableCaching // 开启缓存功能
public class ExceltoolApplication {

    private static final Logger log = org.slf4j.LoggerFactory.getLogger(ExceltoolApplication.class);

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

}
@Cacheable(value="cacheSpace",key="#id") 
public Book getById(Integer id){
    return bookDto.selectById(id);
}

 数据淘汰策略

  • LRU 挑选最近最少使用的数据淘汰
  • LFU 挑选最近使用次数最少的数据淘汰
  • TTL 挑选要过期的淘汰
  • RANDOM 随机淘太

使用redis做缓存

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
cache:
	type:redis
	use-key-prefix:true  #是否使用前缀 
	cache-null-values:false #是否缓存空值
	key-prefix:sys_    #指定key的前缀 必须使用 以防乱套
	tiem-to-live:10s  # 设置缓存过期时间
redis:
	host:localhost
	port:6379
#直接使用即可,缓存数据存储到redis 	

使用memcached做缓存  

1、下载安装

2、客户端选择

Memcached Client for java :最早期的客户端,稳定可靠,用户群广
SpyMemcached :效率更高
XMemcached: 并发处理更好  #推荐选择
<!--选择客户端-->
<dependency>
   <groupId>com.googlecode.xmemcached</groupId>
   <artifactId>xmencached</artifactId>
   <version>2.4.7</version>
</dependency>
@Configuration
public class XMemcachedConfig{
    @Bean
    public MemcacheClient getMemcacheClient() throws IOException{
        MemcachedClientBuilder memcachedClientBuilder = new XMemcachedClientBilder("localhost:11211");
        MemcacheClient memcacheClient = memcachedClientBuilder.build();
        return memcacheClient;
    }
}

 使用memcache

 // expire 0代表永不过期  放入缓存
memcacheClient.set(key,expire,value)
// 取出缓存
memcacheClient.get(key);   

定时任务

java本身的Timer可以实现定时任务(java.util.Timer),其他定时任务,封装了Timer,进行了专业封装 比如 quartz

Timer timer = new Timer();
TimerTask task = new TimerTask(){
    public void run{
        System.out.println("XXXX")
    }
    //2s一次
    timer.schedule(task,0,2000); 
}

整合quartz  

相关概念

  • 工作(job):用于具体执行的工作

  • 工作明细(JobDetail):用于描述定时工作相关的信息

  • 触发器(Tigger):用于描述触发工作的规则,通常使用cron表达式定义调度

  • 调度器(Scheduler):描述工作明细和触发器的对应关系

关系 任务job绑定 工作明细 ,工作明细绑定触发器 并指定Scheduler

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-quarz</artifactId>
</dependency>
public class MyQuartz extends QuartzJobBean{
    // 具体任务job
    protected void executeInternal(JobExecutionContext context) throws JobExectionException{
       System.out.println("xxxx") 
    }
} 
@Configuration
public class QuartzConfig{
    //工作明细bean 要绑定具体的工作任务
    @Bean
    public JobDetail printJobDetail(){
        return JobBuilder.newJob(MyQuartz.class).storeDurably().build();
    }
    
    // 触发器Bean
    @Bean
    public Trigger printTigger(){
        // 绑定具体的工作明细
        ScheduleBuilder schedBuilder = CronScheduleBuilder.cronSchedule("0/15 * * * * ?);
        return TriggerBuilder.newTrigger().forJob(printJobDetail).withSchedule(schedBuilder).build();
    }
    
}

 整合Spring Task

@SpringBootApplication
@EnableScheduling // 开启定时任务开关
public class ExceltoolApplication {

    public static void main(String[] args) {
        SpringApplication.run(ExceltoolApplication.class, args);
    }
}
@Component
public class testSchedule{
    
  @Scheduled(cron = "0 0 * * * ?")
   public void print(){
       System.out.println("123213");
   } 
}

发送邮件

概念

  • SMTP(Simple Mail Transfer Protocol):简单邮件传输协议,用于发送电子邮件的传输协议
  • POP3(Post Office Protocol - Version 3 ):用于接收电子邮件的标准协议
  • IMAP (Internet Mail Access Protocol): 互联网消息协议,是POP3的替代协议

springBoot整合JavaMail

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

配置 

spring:
	mail:
		host:smtp.qq.com
		username:jock
		# 邮件服务器提供的授权码
		password:ewdrtfgjaskd

发送邮件 

public class Send{
    @Autowired 
    private JavaMailSender javaMailSender;
   
    // 发送人
    private String from = "XXX@213432.com";
    // 接收人
    private String to = "xxx@.com";
    // 标题
    private String subject = "测试邮件";
    // 正文    
    private String context = "测试邮件正文" ;
    
    private File f1 = new File("C:\\XXX");
    
    private File f2 = new File("C:\\XXX");
 	
    public void sendSimpleMessage(){
        //发送简单消息
    	SimpleMailMessage  simpleMailMessage = new SimpleMailMessage();
        simpleMailMessage.setFrom(from);
        simpleMailMessage.setTo(to);
        simpleMailMessage.setSubject(subject);
        simpleMailMessage.setText(context);
    	javaMailSender.send(simpleMailMessage);
    }
    
    public void sendMail(){
        // 发送复杂邮件
        MimeMessage message = javaMailSender.createMimeMessage();
        // true 代表可以发送附件
        MimeMessageHelper helper = new MimeMessageHelper(meaage,true);
        helper.setFrom(from);
        helper.setTo(to);
        helper.setSubject(subject);
        helper.setText(context);  // 可以发送图片 setText(context,true); true为html
        // 添加附件
        helper.addAttachment(f1.getName(),f1);
        helper.addAttachment(f2.getName(),f2)
        javaMailSender.send(message);
    }
}

消息处理 

业务系统接到请求之后,不是马上执行,而是将消息推送到消息队列(mq),消费者在订阅消息,处理业务

企业中广泛使用的三种异步消息传递技术

JMS规范   ActiveMQ RabbitMQ RocketMQ(没有完全遵守)
AMQP协议 一种协议,高级消息队列协议,规范了网络交换的数据格式,兼容JMS 跨平台,消费者可以使用不同语言来实现 RabbitMQ RocketMQ
MQTT规范  消息队列遥测传输,专为小设备,专用于物联网  

整合RabbitMQ

<dependency>
	<groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
spring:
	rabbitmq:
		host: localhost
		port:5672
@Configuration
public class RabbitConfigDirect{
    // 队列
    @Bean
    public Queue directQueue(){  
        return new Queue("direct_queue");
    }
    // 交换机
    @Bean
    public DirectExchange directExChange(){
        return new DirectExchange("directExChange");
    }
    // 队列绑定交换机
    @Bean
    public Binding bindingDirect(){
        return BindingBuilder.bind(directQueue()).to(directExChange()).with("direct");  // 改为topic 代表topic类型
    }
}

public class sendMq{
    
   @Autowired
    private AmqpTemplate amqpTemplate;
    
    public void sendMessage(String id){
        amqpTemplate.convertAndSend("directExChange","direct",id);
    }
}
--------listener
@Componemt
public class MessageListener{
    @RabbitListener(queues="direct_queue")
    public void receive(String id){
        System.out.println("已经完成发送业务"+ id);
    }
}

监控

 监控的意义

监控服务状态是否宕机
监控服务运行指标(内存、虚拟机、线程、请求等)
监控日志
管理服务(服务下线)

可视化监控平台 Spring -boot-admin(不是spring-boot官方维护的)

服务端

<!--服务端-->
<dependency>
	<groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-server</artifactId>
    <version>2.5.4</version>  // 一定要和springboot版本一致 否则无法使用
</dependency>
// 服务端
@SpringBootApplication
@EnableAdminServer // 开启监控
public class ExceltoolApplication {

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

}

客户端 

<dependency>
	<groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-client</artifactId>
    <version>2.5.4</version>  // 一定要和springboot版本一致 否则无法使用
</dependency>
spring:
	boot:
		admin:
			client:
				url: http://localhost:8080
#查看健康指标 和开启全部的信息监控
management:
	endpoint:
		htalth:
			show-details: always
	endpoints:
    	web:
    		exposure:
    			inlude: "*"

监控原理

  • Actuator提供了SpringBoot生产就绪功能,通过端点的配置与访问,获取端点信息,
  • 端点描述了一组监控信息,SpringBoot提供了多个内置端点,也可以根据需求自定义端点信息
  • 访问当前应用所有端点信息 /actuator
  • 访问端点详细信息 /actuator/端点名称

springBoot 原理

Bean的加载方式

ApplicationContext.xml 注册bean

<bean id = "cat" class = "com.default.Cat"/>
<bean class="com.default.Dog"/>
<!--声明第三方bean-->
<bean id = datasource class = "com.alibaba.druid.pool.DruidDataSource"/>
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.getBeanDefinitionNames(); // 拿到所有bean定义的名称
ctx.getBean("cat");  // 通过名称获取bean
ctx.getBean(Dog.class); // 通过类型取
ctx.getBean(dog,Dog.class) // 通过类型和名称

注解注册Bean  

@Component("tom") // spring注解
public class Cat{
    
}
<!--指定加载Bean的位置,组件 component  扫描包放入容器中 与@ComponenScan类似-->
<context:component-scan base-package="com,default"/>

 加载第三方bean

@Configuration
public class dbConfig(){
    @Bean
    public DruidDataSource datasource(){
        return  new DruidDataSource();
    }
}

配置类注册bean  

// @Configuration配置项如果不用于被扫描可以省略不加
@ComponentScan({"com.default"}) //配置包扫描放入容器 扫描@Component 衍生注解 @Configuration 加入容器
public class SpringConfig{
    
}

ApplicationContext ctx = new AnnotationConfigApplicationContext("SpringConfig.class");

FactoryBean接口实现了FactoryBean<V>接口的类,造出的对象不是本身,而是泛型上类型的对象

@Bean
public DogFactoryBean dog{
    return new DogFactoryBean();
}
// bean 名不是DogFactoryBean 而是 dog ,可以做环境检测和初始化工作,所以提供了工厂接口

 导入资源注册Bean

@ImportResource("applicationContext.xml") // 导入资源 整合 系统迁移
public class SpringConfig{
    
}
// 冲突问题,如果两个配置文件中都配置了相同名称的bean ,那么 XMl与XMl冲突 后加载的留下 XML与注解冲突,XML留下

 @Configuration proxyBeanMethods

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {

	@AliasFor(annotation = Component.class)
	String value() default "";


	boolean proxyBeanMethods() default true;

}
@Configuration
public class Test{
    @Bean
    public Cat cat{
        return new Cat();
    }
}
对象结果
com.default.Test$$EnhanceBySpringCGLIB$$363d9609@21a1947fe    
test 对象 其实是proxyBeanMethods代理对象 如果 @Configuration(proxyBeanMethods =false)为正常对象  
//如果proxyBeanMethods为true的时候 创建的对象的时候只创建一次,在每次调用在容器中拿到现有对象,保证只有一个对象必须有@Bean,去容器中拿对象,如果没有@Bean 跟@Component效果一样,每次重新创建,如果为false,则每次调用创建一个对象    

@Import配置Bean  

@Import(Cat.class) // 只需要一个注解 就可以加入spring容器
public class SpringConfig{
    
}
ApplicationContext ctx = new AnnotationConfigApplicationContext("SpringConfig.class");
@Import创建的bena是全路径类名

上下文对象注册bean  

ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
ctx.registerBean("tom",Cat.class,0);
ctx.registerBean("tom",Cat.class,1);
ctx.registerBean("tom",Cat.class,2);
ctx.register(Mouse.class); 
// 注册多个bean的只保留2,后边的对象覆盖前边的对象

 实现ImportSelector注册Bean

public class myImportSelector implements ImportSelector{
    
    public String [] selectImports(AnnotationMetadata importingClassMetadata){
       // selectImports 选择器 可以做一系列判定,决定是否加载Bean
       return new String[]{"com.defautlt.Cat"};
    }
}
@Import(myImportSelector.class) 
public class SpringConfig{
    
}
ApplicationContext ctx = new AnnotationConfigApplicationContext("SpringConfig.class");
// 可以做自定义创建Bean 能够通过元数据AnnotationMetadata 获取类的所有信息

实现ImportBeanDefinitionRegistrar接口注册Bean  

// 该接口内部全是默认方法
public interface ImportBeanDefinitionRegistrar {

	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
			BeanNameGenerator importBeanNameGenerator) {

		registerBeanDefinitions(importingClassMetadata, registry);
	}

	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
	}

}
public class MyRegister implements ImportBeanDefinitionRegistrar{
    // 元数据对象 通过registry对象注册对象
   public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		//1、 使用元数据对象判断
        //2、创建 BeanDefinition对象
       BeanDefinition beanDefinition = BeanDefinitionBulider.rootBeanDefinition(Dog.class).getBeanDefinition();
        //3、注册bean
       registry.registerBeanDefinition("yellow",beanDefinition);
   }
}

@Import(MyRegister.class) 
public class SpringConfig{
    
}
ApplicationContext ctx = new AnnotationConfigApplicationContext("SpringConfig.class");

 实现BeanDefinitionRegistryPostProcessor注册Bean

// bean注册完以后
public class MyRegister implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        // bean定义对象
       BeanDefinition beanDefinition = BeanDefinitionBulider.rootBeanDefinition(Dog.class).getBeanDefinition();
        //3、注册bean
       registry.registerBeanDefinition("yellow",beanDefinition); 
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}

@Import(MyRegister.class) 
public class SpringConfig{
    
}
ApplicationContext ctx = new AnnotationConfigApplicationContext("SpringConfig.class");

//bean后处理器,做保底对像,可以覆盖之前定义的对象

Bean加载控制

使用@Conditional选择性加载Bean

public class SpringConfig{
    @ConditionalOnMissingClass("com.default.Cat")
    public Cat tom(){
        return new Cat();
    }
}

 Bean属性设置

1、通过读取配置实现属性的注入
@ConfigurationProperties("test")   
2、单独创建属性类 自动注入属性对象,构造器注入
 public Test(Myproperties myproperties){
    cat = new Cat;
    cat.setName(myproperties.getCat().getName()?myproperties.getCat().getName():"tom")
}   

自动配置原理

1、初始化springBoot基础环境,加载用户自定义的bean和导入的坐标依赖,形成初始化环境

2、将技术集包含的所有技术定义出来,在spring/springBoot启动时默认全部加载

3、将具有使用条件的技术约定出来,设置成条件加载,由开发者决定是否使用该技术

4、将设计集作为默认参数配置,(约定大于配置)减少配置工作量

5、开放设计集配置覆盖接口,由开发者根据自身需要决定是否覆盖默认配置

如果类实现XXXAware接口表示可以使用该资源发现的资源 @oreder 对应bean加载顺序,可能50号bean依赖30号bean 值越小越先加载

定义拦截器

//定义拦截器
public class MyInteceptor implements HandlerInterceptor{
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		return true;
	}

   public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
			@Nullable ModelAndView modelAndView) throws Exception {
	}

}
//将拦截器配置上
@Configuration
public class MyWebMvcConfigurerAdapter implements WebMvcConfigurer {

    /**
     * 添加默认跳转路径
     * @param registry
     */
    @Override
    public  void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(getMyInteceptor()).addPathPatterns("/**");
    }

    @Bean
    public MyInteceptor getMyInteceptor(){
        return new MyInteceptor();
    }
}

启动流程

1、初始化各种属性,加载成对象
  读取环境配置(Environment)
  系统配置(spring.factories)
  参数(Arguments、application.properties)
2、创建Spring容器对象ApplicationContext,加载各种配置
3、在容器创建前,通过监听器机制,应对不同阶段加载数据、更新数据的需求
4、容器初始化过程中追加各种功能,例如统计时间、输出日志等

源码分析

	public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
        // 提升变量作用域
		this.resourceLoader = resourceLoader;
		Assert.notNull(primarySources, "PrimarySources must not be null");
        // 变成集合数据类型操作去重
		this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
        // 一系列判断 返回加载的容器类型
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
        // 读取spring.factories工厂配置初始化 加载系统级引导文件ApplicationContextInitializer实例
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
   		// 初始化监听器的实例对初始化过程和阶段进行干预 不带监听泛型每次都运行,如果干预的话传入泛型,
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
        // 初始化了引导类类名信息,备用
		this.mainApplicationClass = deduceMainApplicationClass();
	}
// 初始化容器,返回上下文对象
public ConfigurableApplicationContext run(String... args) {
    	// 初始化属性
    	// 计时器
		StopWatch stopWatch = new StopWatch(); 
    	// 计时器开始
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
    	//模拟输入输出信号,避免因缺少外设导致信号传输失败引发错误,模拟显示器 键盘 鼠标...
		configureHeadlessProperty();
    	// 获取当前所有可运行的监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
    	//监听器启动
		listeners.starting();
		try {
            // 命令行参数
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
            // 系统环境变量
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
			configureIgnoreBeanInfo(environment);
            // 图标
			Banner printedBanner = printBanner(environment);
            // 创建spring容器 根据判定类型决定
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
            // 对容器进行设置,参数来源于前期设定
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
            // 刷新容器环境
			refreshContext(context);
            // 刷新完毕之后做的后处理
			afterRefresh(context, applicationArguments);
            // 计时器结束
			stopWatch.stop();
			if (this.logStartupInfo) {
                // 输出日志信息包括启动时间
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
            // 将容器加入监听器,可以干预
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值