springBoot基础概念 缓存 邮箱异步处理 定时任务

Spring简介

简化应用开发。去繁从简。just run 就能创建一个独立的产品级别的应用
简化spring应用开发的框架
整个spring的一个大整合
jee开发一站式解决方案
优点
1. 快速创建独立运行的spring项目以及主流框架集成
2. 使用嵌入式Servlet勇气应用无需打war包
3. starters自动依赖和版本控制·
4. 大量的自动配置与版本依赖
5. 无需配置xml 无代码生成开箱即用
6. 准生产环境运行时应用监控
7. 与云计算天然集成

第一个hellowword

我们需要配置一个启动类主程序类
@springBootApplication:标注这个类是springboot的主配置类 我们就应该从这个类的main方法来启动这是一个联合配置
其中包含

SpringBootConfiguration**:Spring Boot的配置类;
标注在某个类上,表示这是一个Spring Boot的配置类;
Configuration**:配置类上来标注这个注解;
配置类 ----- 配置文件;配置类也是容器中的一个组件;@Component
EnableAutoConfiguration:开启自动配置功能;
以前我们需要配置的东西,Spring Boot帮我们自动配置;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能;这样自动配置才能生效;

EnableAutoConfiguration*:开启自动配置功能;
以前我们需要配置的东西,Spring Boot帮我们自动配置;@EnableAutoConfiguration告诉SpringBoot开启自动配置功能;这样自动配置才能生效;
@AutoConfigurationPackage
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
@AutoConfigurationPackage:自动配置包
@Import(AutoConfigurationPackages.Registrar.class):
Spring的底层注解@Import,给容器中导入一个组件;导入的组件由AutoConfigurationPackages.Registrar.class;
将主配置类(@SpringBootApplication标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器;
@Import(EnableAutoConfigurationImportSelector.class);
给容器中导入组件?

EnableAutoConfigurationImportSelector:导入哪些组件的选择器;
将所有需要导入的组件以全类名的方式返回;这些组件就会被添加到容器中;
会给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件,并配置好这些组件; [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rizuFn7X-1629597363600)(images/搜狗截图20180129224104.png)]
有了自动配置类,免去了我们手动编写配置注入功能组件等的工作;
SpringFactoriesLoader.loadFactoryNames(EnableAutoConfiguration.class,classLoader);
==Spring Boot在启动的时候从类路径下的META-INF/spring.factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作;==以前我们需要自己配置的东西,自动配置类都帮我们;
//我们需要配置一个启动类

/*
*  SpringBootApplication 标注这是一个springBoot主程序
*/
@SpringBootApplication
public class Hellow {


    public static void main(String[] args){
        //可以看到我们需要启动一个由@springBootApplication注释标注的类来 启动 
        SpringApplication.run(com.atguigu.Hellow.class,args);


    }
}

第二部我们需要配置一个控制器类

@Controller
public class Hellowcontroller {
     @ResponseBody
     @RequestMapping("hellow")
    public String hellowcontroller(){
        return "hellow 富贵";
    }
}

注解

从配置文件中获取信息分装到bean
使用 @ConfigurationProperties(prefix = “person”) 批量注入prefix指定配置文件中的那个值 注意他必须在ioc容器中 默认是从全局配置从获取值
@value 一个个注入每个属性都要加上 他不支持验证

在这里插入图片描述

场景 :当我需要一个值注入的时候 使用 value

@PropertySource& @ImportResource& @Bean

@propertySource(value={“加载文件路径”}) 这个注解可以加载指定的配置文件 value值可以写一个数组的方式来加载多个配置文件

@ImprotResource({locations=“配置文件路径”}):导入spirng的配置文件让他可以生效 我们以前写一堆配置文件 现在我们需要自己写一个配置文件让他生效我们需要这个注解 他也可以导入多个配置文件 注意 spirng不希望这么做他希望由一个配置类来代替

@Bean 这个注解可以标注在一个方法 或者类上他需要和配置类注解配合使用 方法返回的类就是添加到bean里面的类 方法名为默认id

/**
* @Configuration:指明当前类是一个配置类;就是来替代之前的Spring配置文件
*
* 在配置文件中用<bean><bean/>标签添加组件
*
*/
@Configuration
public class MyAppConfig {


    //将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名
    @Bean
    public HelloService helloService02(){
        System.out.println("配置类@Bean给容器中添加组件了...");
        return new HelloService();
    }
    }

配置文件的占位符

person.last-name=张三${random.uuid}  #我们可以使用random来获取随机数啥的
person.age=${random.int}
person.birth=2017/12/15
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=${person.hello:hello}_dog     #我们可以获取前面配置过得值如果没有默认原样输出 我们还可以通过:来配置他的默认值person.dog.age=15

Profile是spirng对不同环境提供的不同功能的支持 比如开发是开发环境测试是测试环境运营是运营环境
1配置参数方法解决
proerties使用多配置文件的方式 我们可以在文件中通过 定 spring.profiles.active=dev 我们自定义挂坠的文中件生效 自定义挂坠为 application-自定义挂坠.proerties
yml 支持文档块的方式 我们yml语言中—可以分开文档块 通过在文档快来指定我们生效的配置文件例子

server:
  port: 8081      //配置访问端口
spring:
  profiles:
    active: prod  //需要激活的文档快


---
server:
  port: 8083
spring:
  profiles: dev   //自定义文档profiles表示




---


server:
  port: 8084
spring:
  profiles: prod

2、命令行: java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev; 可以直接在测试的时候,配置传入命令行参数
3、虚拟机参数打包完成之后; -Dspring.profiles.active=dev

配置文件

YAML配置文件写法
*
yaml配置文件可以是常量 k:v 双引号""不会转义特殊字符(也就是特殊字符保持他特殊的特性) 但因引号’'会转义特殊字符(特殊符号失去了他的特性回原样子输出)
*
一个map的行内写法 friends:{lastName:张三,age:18}(这个是行内写法可以使用缩进写法)
*
我们可以使用数组写法 使用语法 -

//数组写法的两种方式
friends:
   -wocao
   -nima
//第二种
friends[wocao,nima]

配置可以放在那些位置
在这里插入图片描述
配置互补 配置是可以互补的 高优先级的没有低优先级里面的有 就会生效低优先的也可以通过 配置文件
****spring.config.location=****来选择默认配置文件位置 指定文件位置 和默认文件配置形成互补配置
外部配置加载顺序
在这里插入图片描述

自动配置原理

SpringBoot应用注解@SpringBootApplication是个混合注解实际上分装了三个注解

//四个元注解 链接 https://blog.csdn.net/qq_32371887/article/details/72832928
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented  //java joc工具注解
@Inherited

//配置类注解 实际上是两个注解  @Configuration注解 和@Component @SpringBootConfiguration 与@Component 注解是一样的 SpringBootConfiguration 其实是 Spring Boot 包装的@Configuration 注解 @Component 注解的功能是把普通 POJO 实例化到 Spring 容器中,相当于 配置文件中的<bean id =””class =””/>
@SpringBootConfiguration 

//启动配置类注解
@EnableAutoConfiguration

//组件扫描注解
@ComponentScan(excludeFilters = {
      @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
      @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {

@SpringBootConfiguration:pringBootConfiguration 其实是 Spring Boot 包装的@Configuration 注解 @Component 注 解的功能是把普通 POJO 实例化到 Spring 容器中,相当于 配置文件中的<bean id =””class =””/>
@EnableAutoConfiguration:启动配置类注解 注解可以启用 Spring 应用程序上下文的自动配置, Spring Boot 会去尝试 测和配置你可能需要的 Bean 自动配置类通常是根据类路径中你定 义的 Bean 来推断可能需要怎样的配置 例如,如果在你的类路径中有 tomcat-embedded. 这个类库,那么 Spring Boot 会根据 此信息来判断你可能需要一个 omcatServletWebServerFactory (除非你 已经定义了你自己的 ServletWebServerFactory Bean 。当然我们还可以通过设置 exclude 或者 excludeName 变量 的值来手动排除你不想 的自动配 Spring Boot 默认扫描的包路径是人 口类 DemoOHelloWorldApplication 的根包中, 及其所有的子包 通常, Spring Boot 自动配 Bean 是根据 onditional Bean (条件 Bean) 中注解的类信息来推断的 例如@Conditiona!OnClass 、@Conditiona!OnMissingBean 注解 源码分析 https://blog.csdn.net/ws008/article/details/80007949

@SuppressWarnings("deprecation")
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //这个里面导入了一个类AutoConfigurationPackages

//将我们所有配置@Configuration导入到一个场景  这就和我们吧多个xml导入到一个xml一样
@Import(EnableAutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
  //是否启用自动配置的总开关名
   String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
   //需要排除的自动配置类
   Class<?>[] exclude() default {};
    //需要排除的自动配置类类名
   String[] excludeName() default {};
}

可以看到他导入了一个选择器类EnableAutoConfigurationImportSelector.class
@ComponentScan 提供的功能与 Spring XML 配置文件中的<context: component scan>元素等价 对应 ComponentScan 注解的处理类是 ConfigurationClassParser ComponentScan 告诉 Spring 去哪个 package 下面扫描 Spring 注解 Spring 会去自动扫描这 些被 Spring 注解标注的类,并且将其注册到 Bean 容器中 如果你有个类用@Controller 注解标识了,但是没有加上@ComponentScan 告诉 Spring 扫描这个类所在的包,那么该 Controller 就不会被注册到 Spring 容器中 不过, Spring Boot 中如果不显式地使用@ComponentScan 指明对象扫描的包,那么默 认只扫描当前启动类所在的包里的类 我们可以设置 basePackageC!asses 的值来指定要扫描哪个类所在的包,

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
   /**

    * 对应的包扫描路径 可以是单个路径,也可以是扫描的路径数组

    * @return

    */
   @AliasFor("basePackages")
   String[] value() default {};
   /**

    * 和value一样是对应的包扫描路径 可以是单个路径,也可以是扫描的路径数组

    * @return

    */
   @AliasFor("value")
   String[] basePackages() default {};
   /**

    * 指定具体的扫描的类

    * @return

    */
   Class<?>[] basePackageClasses() default {};
   /**

    * 对应的bean名称的生成器 默认的是BeanNameGenerator

    * @return

日志包

//记录

Logger logger = LoggerFactory.getLogger(getClass());
@Test
public void contextLoads() {
   //System.out.println();


   //日志的级别;
   //由低到高   trace<debug<info<warn<error
   //可以调整输出的日志级别;日志就只会在这个级别以以后的高级别生效
   logger.trace("这是trace日志...");
   logger.debug("这是debug日志...");
   //SpringBoot默认给我们使用的是info级别的,没有指定级别的就用SpringBoot默认规定的级别;root级别
   logger.info("这是info日志...");
   logger.warn("这是warn日志...");
   logger.error("这是error日志...");
   }

可以在配置文件里面 配置的日志选项

logging.level.com.atguigu=trace  #指定日志级别
#spring.profiles.active=dev #指定开发文件


#logging.path=
# 不指定路径在当前项目下生成springboot.log日志
# 可以指定完整的路径;
#logging.file=G:/springboot.log
# 在当前磁盘的根路径下创建spring文件夹和里面的log文件夹;使用?spring.log 作为默认文件
logging.path=/spring/log


#  在控制台输出的日志的格式 详细看博客
logging.pattern.console=%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n
# 指定文件中日志输出的格式
logging.pattern.file=%d{yyyy-MM-dd} === [%thread] === %-5level === %logger{50} ==== %msg%n

指定配置文件

在这里插入图片描述
关于包的切换 只需要在meven里面删除 web_start里面里面的依赖就行 然后倒入新的日志具体关系图
在这里插入图片描述
关于操作的图 spring默认使用logback记录日志
在这里插入图片描述
以上切换不用具体了解 知道他需要中间适配包就行 想换框架啥的直接删除boot启动器的日志包重新在meven配置文件里面自己导入想要的

spirngboot静态资源导入

1.所有的静态资源都已 jar包的方式放入 所有的 /wabjars/**classpath:/META-INF/resources/webjars/ 找资源
在这里插入图片描述

springBoot配置 静态资源映射

spring.resources.static-locations= calsspaht:/hellow ,classpath:/yongli

模板引擎

在这里插入图片描述
这些个模板引擎是 都是通过一个解释器来运行到 springBoot推线使用Thymeleaf
Thymeleaf
https://blog.csdn.net/mynameissls/article/details/72880647 这里面有简单的使用方法
https://blog.csdn.net/chaoqunyu/article/details/79066996

配置springmvc

org.springframework.boot.autoconfigure.web:web的所有自动场景;
spring帮我们配置好了springmvc配置类但是只有这些配置他是远远不够的springmvc默认配置类为WebMvcAutoConfiguration 我们可以通过向容器里面注入这个类然后配置 来解决我们的配置问题 原有配置和现有配置都会起作用 因为springboot 会获取所有的WebMvcAutoConfiguration类 前提是我们不能标注他是个配置类的时候不能添加@EnableWebMvc 这回让springboot自己配置的类失效 只使用我们配置的类
springboot1.x版本

@Override
    public void addViewControllers(ViewControllerRegistry registry) {
       // super.addViewControllers(registry);
        //浏览器发送 /atguigu 请求来到 success
        registry.addViewController("/atguigu").setViewName("success");
    }
    //所有的WebMvcConfigurerAdapter组件都会一起起作用
    @Bean //将组件注册在容器
    public WebMvcConfigurerAdapter webMvcConfigurerAdapter(){
        WebMvcConfigurerAdapter adapter = new WebMvcConfigurerAdapter() {
            @Override
            public void addViewControllers(ViewControllerRegistry registry) {
                registry.addViewController("/").setViewName("login");
                registry.addViewController("/index.html").setViewName("login");
            }
        };
        return adapter;
    }
}

springboot2.x版本

package com.chenzhu2.user.config;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

    @Configuration
    public class MymvcConfiurer implements WebMvcConfigurer {
        @Override
        public void addViewControllers(ViewControllerRegistry registry) {
            registry.addViewController("/abc").setViewName("success");
        }


        @Bean //将组件注册在容器
        public WebMvcConfigurer webMvcConfigurerAdapter(){
            WebMvcConfigurer adapter = new WebMvcConfigurer() {
                @Override
                public void addViewControllers(ViewControllerRegistry registry) {
                    registry.addViewController("/").setViewName("success");
                    registry.addViewController("/index.html").setViewName("success");
                }
            };
            return adapter;
        }
    }

自动配置国际化

配置javaweb 三大组件 servlet filter Listener 注册serlvet 把自定义的serlvet 放入 ServletRegistrationBean

//注册三大组件
@Bean
public ServletRegistrationBean myServlet(){
    ServletRegistrationBean registrationBean = new ServletRegistrationBean(new
MyServlet(),"/myServlet"); //第一个参数必须是一个serlvet处理器这个后面表示serlvet需要处理的请求
    return registrationBean;
}

注册Filter 需要吧filter放入 FilterRegistrationBean

@Bean
public FilterRegistrationBean myFilter(){
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    registrationBean.setFilter(new MyFilter());
    registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
    return registrationBean;
}

注册Listener ServletListenerRegistrationBean放入我们的listener

@Bean
public ServletListenerRegistrationBean myListener(){
    ServletListenerRegistrationBean<MyListener> registrationBean = new
ServletListenerRegistrationBean<>(new MyListener());
    r

spring数据和访问

当我们配置好了数据源信息之后springboot会自动帮我们配置JdbcTemplate类放入ioc容器

jdbc

下面是自己导入的jdbc依赖和 mysql驱动

<dependency>
<groupId>org.springframework.boot</groupId>            
<artifactId>spring‐boot‐starter‐jdbc</artifactId>            
</dependency>        
<dependency>        
<groupId>mysql</groupId>            
<artifactId>mysql‐connector‐java</artifactId>            
<scope>runtime</scope>            
</dependency>

下面是配置数据源yml文件

spring:
  datasource:  //配置数据源
    username: root
    password: abcdef
    url: jdbc:mysql://localhost:3306/springboot?characterEncoding=utf-8&serverTimezone=GMT%2B8
    driver-class-name: com.mysql.cj.jdbc.Driver

自定义数据源这里是druid (只需要吧数据源放进ioc容器就行了)

<!--引入druid数据源-->
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid</artifactId>
   <version>1.1.8</version>
</dependency>
spring:
  datasource:
    username: root
    password: abcdef
    url: jdbc:mysql://localhost:3306/springboot?characterEncoding=utf-8
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource #这个是指定数据源连接池的类型 必须指定不指定的话可能会引用默认的
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

配置类 我们还可以自定义 serlvelt 还有过滤器

@Configuration
public class DruidConfig {


    //引入配置属性在bean里面,因为springboot里面没有黄色的上面配置文件黄色的部分我们采用@ConfigurationProperties来为druid配置
    @ConfigurationProperties(prefix = "spring.datasource") 
    @Bean
    public DruidDataSource druid(){
        return new DruidDataSource();
    }


    //配置Druid的监控
    //1、配置一个管理后台的Servlet 这个serlvet 会有自己后台的一套 就是直接使用html页面啥的都有是很完整的
    @Bean
    public ServletRegistrationBean statViewServlet(){
        ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*"); //StatViewServlet这个serlvet专门配置好的监控数据源后台的 后面是需要处理的请求
        Map<String,String> initParams = new HashMap<>();


        initParams.put("loginUsername","admin");  //设置可以访问的账号
        initParams.put("loginPassword","123456"); //可以访问的密码
        initParams.put("allow","");//默认就是允许所有访问 第二个参数可以填写 只允许那个访问
        initParams.put("deny","192.168.15.21"); //  拒绝那个访问


        bean.setInitParameters(initParams);  //添加到ServletRegistrationBean类里面
        return bean;
    }




    //2、配置一个web监控的filter
    @Bean
    public FilterRegistrationBean webStatFilter(){
        FilterRegistrationBean bean = new FilterRegistrationBean();
        bean.setFilter(new WebStatFilter()); //WebStatFilter() 这个过滤器负责监控web后台数据 比如差了多少条数据啥的


        Map<String,String> initParams = new HashMap<>();
        initParams.put("exclusions","*.js,*.css,/druid/*"); //我们不拦截的请求一般都是静态资源


        bean.setInitParameters(initParams);


        bean.setUrlPatterns(Arrays.asList("/*"));//这是我们拦截的请求


        return  bean;
    }
}

运行项目自动运行sql文件

我们可以把sql文件放到classpath路径下springboot会自动给我们运行起来

shcema-*sql ,date-*sql;
//默认使用规则 shema.sql 和 shcema-all.sql
//指定规则
schema:
        -classpath:department.sql  //这里是指定名字为 department 这是个数族可以指定多个

Springboot缓存

好处:我们有可能就是一个数据需要多次访问 我们总是从数据库查 十分影响性能 我们就回使用缓存
比如我们还有一些临时型的数据如果放到内存中负担太大了

jsr107缓存规则

CachingProvider定义了创建配置获取管理和控制多个CheManager
*
CheManager 定义了创建获取管理和控制多个唯一命名的Cache 这些cache存在于与CheManager这个接口里面 一个cheManager只能对应一个 CachingProvider
*
Cache是一个类似map的数据结构 并临时存储以key的索引值 一个Cache仅仅只能让一个cheManager管理
*
Entry 是一个存在Cache的key-value对
*
Expiry 每一个cache 都有一个定义的有效期 一但超过了这个时间条目为过期状态过期状态条目不可访问,不可操作缓存有效期可以通过ExpiryPolicy设置

总结就是 都是一对多关系 除了最后那两个数据
在这里插入图片描述

spring缓存

spring认为js107缓存结构太复杂就简化了操作

在这里插入图片描述
@Cacheable 比如我们getbyid(1) 如果在这个方法 加上这个注解那个返回的值就会被放入缓存中如果下次在查询这个对象直接从缓存中拿出来(再方法执行之前使用)
@CacheEvict 这个删除缓存 比如说我们删除一个用户这个用户在缓存中还有那么我们就可以使用这个注解标注在删除方法上那么回清空缓存里面关于删除对象的
@CachePut 缓存更行 如果修改了数据库但是缓存中还存在之前的数据 所以我们修改对象时侯加上这个注解那么缓存就也会被更新了先当与更新缓存(在方法执行之后在调用 可以是返回值reult.id获取主键 要与更新缓存中的key一样才能正确的更新,)
@EnableCaching 标注在主类上开启基于缓存的注解
@CacheConfig(cacheNames=“emp”/,cacheManager = “employeeCacheManager”/) 用标注在类上用来指定这个类里面所有注解的公共配置规则
@Caching 定义复杂的缓存规则 可以使用 cacheable属性来指定删改你各个组件的缓存规则 如果 如果同时标注了 @cacheable 和cacheput 那么这个方法就必须执行

@Caching(
         cacheable = {
             @Cacheable(/*value="emp",*/key = "#lastName")
         },
         put = {
             @CachePut(/*value="emp",*/key = "#result.id"),
             @CachePut(/*value="emp",*/key = "#result.email")
         }
    )
    public Employee getEmpByLastName(String lastName){

上面注解共有的属性

cacheNames/value:指定缓存的名字将方法的返回值返回到那缓存区里面是以数组的方式,可以指定多个缓存

key: 缓存数据时候使用的key 可以用它来指定 默认的值为方法参数 1- 方法的返回值 #i d;参数id值 #a0 #p0 #root.args[0]
getEmp[2]

keyGenerator:key的生成器,自己可以指定生成器组件的id 不能和key共同使用 可以通过把自己的keyGenerator添加到ioc容器中

cacheManager:指定缓存管理器 或者cacheResolver获取指定解析器

condition:指定符合条件的情况下才缓存; condition "#id>0"condition = “#a0>1”:第一个参数的值》1的时候才进行缓存 结果 如果为true那么缓存

unless:否定缓存;当unless指定的条件为true,方法的返回值不会被缓存;可以获取到结果进行判断unless = "#result == null"unless = “#a0==2”:如果第一个参数的值是2,结果不缓存 。如果结果为true不缓存

sync:是否使用异步模式

 @Cacheable(value = {"emp"}/*,keyGenerator = "myKeyGenerator",condition = "#a0>1",unless = "#a0==2"*/)
       public Employee getEmp(Integer id){

原理

package com.atguigu.cache.service;


import com.atguigu.cache.bean.Employee;
import com.atguigu.cache.mapper.EmployeeMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;


@CacheConfig(cacheNames="emp"/*,cacheManager = "employeeCacheManager"*/) //抽取缓存的公共配置
@Service
public class EmployeeService {


    @Autowired
    EmployeeMapper employeeMapper;


    /**
     * 将方法的运行结果进行缓存;以后再要相同的数据,直接从缓存中获取,不用调用方法;
     * CacheManager管理多个Cache组件的,对缓存的真正CRUD操作在Cache组件中,每一个缓存组件有自己唯一一个名字;
     *


     *
     * 原理:
     *   1、自动配置类;CacheAutoConfiguration
     *   2、缓存的配置类
     *   org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration
     *   org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration
     *   org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration
     *   org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration
     *   org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration
     *   org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration
     *   org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
     *   org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration
     *   org.springframework.boot.autoconfigure.cache.GuavaCacheConfiguration
     *   org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration【默认】
     *   org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration
     *   3、哪个配置类默认生效:SimpleCacheConfiguration;
     *
     *   4、给容器中注册了一个CacheManager:ConcurrentMapCacheManager
     *   5、可以获取和创建ConcurrentMapCache类型的缓存组件;他的作用将数据保存在ConcurrentMap中;
     *
     *   运行流程:
     *   @Cacheable:
     *   1、方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取;
     *      (CacheManager先获取相应的缓存),第一次获取缓存如果没有Cache组件会自动创建。
     *   2、去Cache中查找缓存的内容,使用一个key,默认就是方法的参数;
     *      key是按照某种策略生成的;默认是使用keyGenerator生成的,默认使用SimpleKeyGenerator生成key;
     *          SimpleKeyGenerator生成key的默认策略;
     *                  如果没有参数;key=new SimpleKey();
     *                  如果有一个参数:key=参数的值
     *                  如果有多个参数:key=new SimpleKey(params);
     *   3、没有查到缓存就调用目标方法;
     *   4、将目标方法返回的结果,放进缓存中
     *
     *   @Cacheable标注的方法执行之前先来检查缓存中有没有这个数据,默认按照参数的值作为key去查询缓存,
     *   如果没有就运行方法并将结果放入缓存;以后再来调用就可以直接使用缓存中的数据;
     *
     *   核心:
     *      1)、使用CacheManager【ConcurrentMapCacheManager】按照名字得到Cache【ConcurrentMapCache】组件
     *      2)、key使用keyGenerator生成的,默认是SimpleKeyGenerator
     *
     *
     *   几个属性:
     *      cacheNames/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存;
     *
     *      key:缓存数据使用的key;可以用它来指定。默认是使用方法参数的值  1-方法的返回值
     *              编写SpEL; #i d;参数id的值   #a0  #p0  #root.args[0]
     *              getEmp[2]
     *
     *      keyGenerator:key的生成器;可以自己指定key的生成器的组件id
     *              key/keyGenerator:二选一使用;
     *
     *
     *      cacheManager:指定缓存管理器;或者cacheResolver指定获取解析器
     *
     *      condition:指定符合条件的情况下才缓存;
     *              ,condition = "#id>0"
     *          condition = "#a0>1":第一个参数的值》1的时候才进行缓存
     *
     *      unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断
     *              unless = "#result == null"
     *              unless = "#a0==2":如果第一个参数的值是2,结果不缓存;
     *      sync:是否使用异步模式
     * @param id
     * @return
     *
     */
    @Cacheable(value = {"emp"}/*,keyGenerator = "myKeyGenerator",condition = "#a0>1",unless = "#a0==2"*/)
    public Employee getEmp(Integer id){
        System.out.println("查询"+id+"号员工");
        Employee emp = employeeMapper.getEmpById(id);
        return emp;
    }


    /**
     * @CachePut:既调用方法,又更新缓存数据;同步更新缓存
     * 修改了数据库的某个数据,同时更新缓存;
     * 运行时机:
     *  1、先调用目标方法
     *  2、将目标方法的结果缓存起来
     *
     * 测试步骤:
     *  1、查询1号员工;查到的结果会放在缓存中;
     *          key:1  value:lastName:张三
     *  2、以后查询还是之前的结果
     *  3、更新1号员工;【lastName:zhangsan;gender:0】
     *          将方法的返回值也放进缓存了;
     *          key:传入的employee对象  值:返回的employee对象;
     *  4、查询1号员工?
     *      应该是更新后的员工;
     *          key = "#employee.id":使用传入的参数的员工id;
     *          key = "#result.id":使用返回后的id
     *             @Cacheable的key是不能用#result
     *      为什么是没更新前的?【1号员工没有在缓存中更新】
     *
     */
    @CachePut(/*value = "emp",*/key = "#result.id")
    public Employee updateEmp(Employee employee){
        System.out.println("updateEmp:"+employee);
        employeeMapper.updateEmp(employee);
        return employee;
    }


    /**
     * @CacheEvict:缓存清除
     *  key:指定要清除的数据
     *  allEntries = true:指定清除这个缓存中所有的数据
     *  beforeInvocation = false:缓存的清除是否在方法之前执行
     *      默认代表缓存清除操作是在方法执行之后执行;如果出现异常缓存就不会清除
     *
     *  beforeInvocation = true:
     *      代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除
     *
     *
     */
    @CacheEvict(value="emp",beforeInvocation = true/*key = "#id",*/)
    public void deleteEmp(Integer id){
        System.out.println("deleteEmp:"+id);
        //employeeMapper.deleteEmpById(id);
        int i = 10/0;
    }


    // @Caching 定义复杂的缓存规则
    @Caching(
         cacheable = {
             @Cacheable(/*value="emp",*/key = "#lastName")
         },
         put = {
             @CachePut(/*value="emp",*/key = "#result.id"),
             @CachePut(/*value="emp",*/key = "#result.email")
         }
    )
    public Employee getEmpByLastName(String lastName){
        return employeeMapper.getEmpByLastName(lastName);
    }
}


springboot和任务 执行异步任务

在启动类加上 @EnableAsync 开启异步注解功能
在需要异步的方法上写入 @Async声明这是一个异步任务

@Service
public class AsyncService {
    //告诉Spring这是一个异步方法
    @Async
    public void hello(){}

执行定时任务

项目开发中时常有一些定时任务,比如需要在每天凌晨的时候分析一次一天的日志信息 spring 为我们提供了 异步执行的任务调度方式 。提供了taskExecutor,TaskScheduler接口
注解 @EnableScheduling 和 @Scheduled
主启动类上面加上@EnableScheduling

@EnableScheduling //开启基于注解的定时任务
@SpringBootApplication
public class Springboot04TaskApplication {


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

使用@Scheduled确定访问的时间

/**
  * second(秒), minute(分), hour(时), day of month(日), month(月), day of week(周几).
  * 0 * * * * MON-FRI
  *  【0 0/5 14,18 * * ?】 每天14点整,和18点整,每隔5分钟执行一次
  *  【0 15 10 ? * 1-6】 每个月的周一至周六10:15分执行一次
  *  【0 0 2 ? * 6L】每个月的最后一个周六凌晨2点执行一次
  *  【0 0 2 LW * ?】每个月的最后一个工作日凌晨2点执行一次
  *  【0 0 2-4 ? * 1#1】每个月的第一个周一凌晨2点到4点期间,每个整点都执行一次;
  */
// @Scheduled(cron = "0 * * * * MON-SAT")
//@Scheduled(cron = "0,1,2,3,4 * * * * MON-SAT")
// @Scheduled(cron = "0-4 * * * * MON-SAT")
@Scheduled(cron = "0/4 * * * * MON-SAT")  //每4秒执行一次
public void hello(){
     System.out.println("hello ... ");
}

邮件发送

导入依赖

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

配置邮箱地址

[email protected]  //账号
spring.mail.password=gtstkoszjelabijb  //密码
spring.mail.host=smtp.qq.com           //授权码
spring.mail.properties.mail.smtp.ssl.enable=true//开启安全连接 目前知道的qq邮箱必须开启

发送邮箱

@Autowired
JavaMailSenderImpl mailSender;

    SimpleMailMessage message = new SimpleMailMessage();
   //邮件设置
   message.setSubject("通知-今晚开会");
   message.setText("今晚7:30开会");


   message.setTo("[email protected]");
   message.setFrom("[email protected]");


   mailSender.send(message);
}


*****************************************************
//1、创建一个复杂的消息邮件
MimeMessage mimeMessage = mailSender.createMimeMessage();
  
MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true);//第二个参数是是否上传文件


//邮件设置
helper.setSubject("通知-今晚开会");

helper.setText("<b style='color:red'>今天 7:30 开会</b>",true);//如果设置内容为网页输出填入 true 这个选择是 true 如果你想要原样输出选择false


helper.setTo("[email protected]");//消息发送给那个邮箱
helper.setFrom("[email protected]");//填入自己的邮箱地址


//上传文件
helper.addAttachment("1.jpg",new File("C:\\Users\\lfy\\Pictures\\Saved Pictures\\1.jpg"));
helper.addAttachment("2.jpg",new File("C:\\Users\\lfy\\Pictures\\Saved Pictures\\2.jpg"));


mailSender.send(mimeMessage);

猜你喜欢

转载自blog.csdn.net/weixin_43979902/article/details/119848897
今日推荐