16_Spring Boot整合篇

1 spring boot整合jdbc

1.1 导入的maven依赖

<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>

1.2 配置相关数据源:

spring:
  datasource:
    username: root
    data-password: 123456
    url: jdbc:mysql://47.104.128.12:3306/tuling-vip
    driver-class-name: com.mysql.jdbc.Driver

1.3 测试

@Autowired
private DataSource dataSource;
@Test
public void contextLoads() {
}
@Test
public void testDbType() {
    System.out.println("自动装配数据源的类型:"+dataSource.getClass());
}

1.4 jdbc以及数据源的自动装配原理

1.4.1 数据源的自动装配

/**
 * Tomcat Pool DataSource configuration.
 */
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource")
static class Tomcat {
    //配置tomcat 连接池的数据源
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.tomcat")

    public org.apache.tomcat.jdbc.pool.DataSource dataSource(DataSourceProperties properties) {
        org.apache.tomcat.jdbc.pool.DataSource dataSource = createDataSource(properties, org.apache.tomcat.jdbc.pool.DataSource.class);
        DatabaseDriver databaseDriver = DatabaseDriver
                .fromJdbcUrl(properties.determineUrl());
        String validationQuery = databaseDriver.getValidationQuery();
        if (validationQuery != null) {
            dataSource.setTestOnBorrow(true);
            dataSource.setValidationQuery(validationQuery);
        }
        return dataSource;
    }

}

/**
 * Hikari DataSource configuration.
 */
@ConditionalOnClass(HikariDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.zaxxer.hikari.HikariDataSource", matchIfMissing = true)
static class Hikari {
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    public HikariDataSource dataSource(DataSourceProperties properties) {
        HikariDataSource dataSource = createDataSource(properties,
                HikariDataSource.class);
        if (StringUtils.hasText(properties.getName())) {
            dataSource.setPoolName(properties.getName());
        }
        return dataSource;
    }

}

/**
 * DBCP DataSource configuration.
 */
@ConditionalOnClass(org.apache.commons.dbcp2.BasicDataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "org.apache.commons.dbcp2.BasicDataSource", matchIfMissing = true)
static class Dbcp2 {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.dbcp2")
    public org.apache.commons.dbcp2.BasicDataSource dataSource(
            DataSourceProperties properties) {
        return createDataSource(properties,
                org.apache.commons.dbcp2.BasicDataSource.class);
    }

}

//通过spring.dataSource.tpye 来指定装配的数据源
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {

    @Bean
    public DataSource dataSource(DataSourceProperties properties) {

        return properties.initializeDataSourceBuilder().build();
    }

}

    //用于整合druid 等数据源配置的
    public DataSourceBuilder<?> initializeDataSourceBuilder() {
        return DataSourceBuilder.create(getClassLoader()).type(getType())
                .driverClassName(determineDriverClassName()).url(determineUrl())
                .username(determineUsername()).password(determinePassword());
    }

    public T build() {
        //数据源类型
        Class<? extends DataSource> type = getType();
        //通过反射创建数据源
        DataSource result = BeanUtils.instantiateClass(type);
        maybeGetDriverClassName();
        bind(result);
        return (T) result;
    }

1.4.2 jdbcTemplate自动装配

@Configuration
@ConditionalOnClass({ DataSource.class, JdbcTemplate.class })
@ConditionalOnSingleCandidate(DataSource.class)
@AutoConfigureAfter(DataSourceAutoConfiguration.class)
@EnableConfigurationProperties(JdbcProperties.class)
public class JdbcTemplateAutoConfiguration {
    @Configuration
    static class JdbcTemplateConfiguration {
        private final DataSource dataSource;
        private final JdbcProperties properties;
        JdbcTemplateConfiguration(DataSource dataSource, JdbcProperties properties) { this.dataSource = dataSource;
            this.properties = properties;
        }
        //jdbcTemplate 配置
        @Bean
        @Primary
        @ConditionalOnMissingBean(JdbcOperations.class)
        public JdbcTemplate jdbcTemplate() {
            JdbcTemplate jdbcTemplate = new JdbcTemplate(this.dataSource); JdbcProperties.Template template = this.properties.getTemplate(); jdbcTemplate.setFetchSize(template.getFetchSize());                       jdbcTemplate.setMaxRows(template.getMaxRows());
            if (template.getQueryTimeout() != null) {
                jdbcTemplate
                        .setQueryTimeout((int) template.getQueryTimeout().getSeconds()); }
            return jdbcTemplate;
        }
    }
    @Configuration
    @Import(JdbcTemplateConfiguration.class)
    static class NamedParameterJdbcTemplateConfiguration {
        @Bean
        @Primary
        @ConditionalOnSingleCandidate(JdbcTemplate.class)
        @ConditionalOnMissingBean(NamedParameterJdbcOperations.class)
        public NamedParameterJdbcTemplate namedParameterJdbcTemplate(
                JdbcTemplate jdbcTemplate) {
            return new NamedParameterJdbcTemplate(jdbcTemplate);
        }
    }
}

测试:

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Test
    public void testDbType() {
        System.out.println("自动装配数据源的类型:"+dataSource.getClass());
    }
    @Test
    public void testJdbcTemplate() {
        List<Map<String,Object>> employeeList = jdbcTemplate.queryForList("select * from employee")
        System.out.println(employeeList.size());
    }

2 springboot如何优雅的整合druid+监控

2.1 加入druid的依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1. 1. 10</version>
</dependency>
<!--自定义属性绑定配置-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

2.2 配置druid的数据源属性

在这里插入图片描述

我们发现上面部分 红框 部分是显示黄色 , 在datasource.properties的文件中 , 没有属性进行一一映射
在这里插入图片描述

所以我们看到的带红框部分是没有映射到数据源中.
在这里插入图片描述

2.3)解决办法(优雅)就是我们自己配置一个druid数据源

spring:
  datasource:
    druid:
      username: root
      password: 123456
      url: jdbc:mysql://47.104.128.12:3306/tuling-vip
      driverClassName: com.mysql.jdbc.Driver
      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
      #   配置监控统计拦截的filters, 去掉后监控界面sql无法统计, 'wall'用于防火墙
      filters: stat,wall,log4j
      maxPoolPreparedStatementPerConnectionSize: 20
      useGlobalDataSourceStat: true
      connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

对应的接受配置类(省略了getSet方法…)

@ConfigurationProperties(prefix = "spring.datasource.druid")  
//扫描配置类的属性前缀
public class DruidDataSourceProperties {
    private String username;
    private String password;

    private String jdbcUrl;
    private String driverClassName;
    private Integer initialSize;
    private Integer maxActive;
    private Integer minIdle;
    private long maxWait;
    private boolean poolPreparedStatements;
}

自己定制一个druid的配置类

@Configuration
@EnableConfigurationProperties(value = DruidDataSourceProperties.class)
public class DruidDataSourceConfig {
    @Autowired
    private DruidDataSourceProperties druidDataSourceProperties;
    @Bean
    public DataSource dataSource() {
        System.out.println(druidDataSourceProperties);
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setUsername(druidDataSourceProperties.getUsername());
        druidDataSource.setPassword(druidDataSourceProperties.getPassword());
        druidDataSource.setUrl(druidDataSourceProperties.getJdbcUrl());
        druidDataSource.setDriverClassName(druidDataSourceProperties.getDriverClassName()); druidDataSource.setInitialSize(druidDataSourceProperties.getInitialSize());                        druidDataSource.setMinIdle(druidDataSourceProperties.getMinIdle());                               druidDataSource.setMaxActive(druidDataSourceProperties.getMaxActive());                      druidDataSource.setMaxWait(druidDataSourceProperties.getMaxWait());
        druidDataSourceProperties.setPoolPreparedStatements(druidDataSourceProperties.isPoolPreparedState return druidDataSource;
    }
}

再来查看对应的数据源的属性 已经成功的映射到数据源中

在这里插入图片描述

2.4)配置数据源监控 , 配置一个statViewSerlvet(后端管理) WebStatFilter sql监控


    /**
     * 配置druid管理后台的servlet
     * @return
     */
    @Bean
    public ServletRegistrationBean statViewSerlvet() {
        ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
        Map<String, Object> initParameters = new HashMap<>();
        initParameters.put("loginUsername", "admin");
        initParameters.put("loginPassword", "123456");
        bean.setInitParameters(initParameters);
        return bean;
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
        filterRegistrationBean.setUrlPatterns(Arrays.asList("/*"));
        Map<String, Object> initParams = new HashMap<>();
        initParams.put("exclusions", "*.js,*.css,/druid/*");
        filterRegistrationBean.setInitParameters(initParams);
        return filterRegistrationBean;
    }

监控访问路径:http://localhost:8080/druid/

在这里插入图片描述

3 spring boot整合 mybaits

3.1 导入maven依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.0.0</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
    <version>5. 1.46</version>
</dependency>

3.2 让我们看下mybatis自动配置类给我们配置了什么组件

①:导入了SqlSessionFactory
②:导入了sqlSessionTemplate
③:导入了mapperScanner

@AutoConfigureAfter(DataSourceAutoConfiguration.class)
public class MybatisAutoConfiguration implements InitializingBean {

    // 1:自动装配了 sqlSessionFactory
    @Bean
    @ConditionalOnMissingBean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
        factory.setDataSource(dataSource);
        factory.setVfs(SpringBootVFS.class);
        if (StringUtils.hasText(this.properties.getConfigLocation())) {
            factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
        }
        applyConfiguration(factory);
        if (this.properties.getConfigurationProperties() != null) {
            factory.setConfigurationProperties(this.properties.getConfigurationProperties());
        }
        if (!ObjectUtils.isEmpty(this.interceptors)) {
            factory.setPlugins(this.interceptors);
        }
        if (this.databaseIdProvider != null) {
            factory.setDatabaseIdProvider(this.databaseIdProvider);
        }
        if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
            factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
        }
        if (this.properties.getTypeAliasesSuperType() != null) {
            factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
        }
        if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
            factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
        }
        if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
            factory.setMapperLocations(this.properties.resolveMapperLocations());
        }
        return factory.getObject();
    }

    //2:配置了sqlSessionTemplate
    @Bean
    @ConditionalOnMissingBean
    public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) {
        ExecutorType executorType = this.properties.getExecutorType();
        if (executorType != null) {
            return new SqlSessionTemplate(sqlSessionFactory, executorType);
        } else {
            return new SqlSessionTemplate(sqlSessionFactory);
        }
    }

    //3:自动装配 导入mapperScanner
    public static class AutoConfiguredMapperScannerRegistrar
            implements BeanFactoryAware, ImportBeanDefinitionRegistrar, ResourceLoaderAware {
        private BeanFactory beanFactory;
        private ResourceLoader resourceLoader;

        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            if (!AutoConfigurationPackages.has(this.beanFactory)) {
                logger.debug("Could not determine auto-configuration package, automatic mapper scanning disabled.");
                return;
            }
            logger.debug("Searching for mappers annotated with @Mapper");
            List<String> packages = AutoConfigurationPackages.get(this.beanFactory);
            if (logger.isDebugEnabled()) {
                packages.forEach(pkg -> logger.debug("Using auto-configuration base package '{}'", pkg));
            }
            ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry);
            if (this.resourceLoader != null) {
                scanner.setResourceLoader(this.resourceLoader);
            }
            scanner.setAnnotationClass(Mapper.class);
            scanner.registerFilters();
            scanner.doScan(StringUtils.toStringArray(packages));
        }
    }
}

3.3 把sql写在方法上(mapper文件上必须加上@Mapper注解)

@Mapper
public interface EmployeeMapper {
    @Select("select * from employee")
    List<Employee> list();

    @Select("select * from employee where id=#{id}")
    Employee findOne(Integer id);

    @Options(useGeneratedKeys = true, keyProperty = "id")
    @Insert("insert into employee(last_name,email,gender,dept_id)values(#{lastName},#{email},#{gender},#{deptId})")
    int save(Employee employee);
}

3.4 把sql写在配置文件上

需要制定配置文件位置

#配置mybatis
mybatis:
  configuration:
    map-underscore-to-camel-case: true  #开启驼峰命名
  mapper-locations: classpath:/mybatis/mapper/*.xml  #指定配置文件的位置

4 整合Redis

4.1 导入的maven依赖

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

4.2 自动装配的组件

@Configuration
@ConditionalOnClass(RedisOperations.class)
@EnableConfigurationProperties(RedisProperties.class)
@Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
    // 1:自动装配了redis的操作模板类
    @Bean
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(
            RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    // 2:自动装配了StringRedisTemplate模板类
    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(
            RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

@Configuration
@ConditionalOnClass({GenericObjectPool.class, JedisConnection.class, Jedis.class})
class JedisConnectionConfiguration extends RedisConnectionConfiguration {
    // redis的链接工厂
    @Bean
    @ConditionalOnMissingBean(RedisConnectionFactory.class)
    public JedisConnectionFactory redisConnectionFactory() throws UnknownHostException {
        return createJedisConnectionFactory();
    }
}

4.3 所需的配置类,我们去RedisProperties配置类 看下可以具体配置哪些属性

@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
    private int database = 0;
    private String url;
    private String host = "localhost";
    private String password;
    private int port = 6379;
    private boolean ssl;
    private Duration timeout;
    private Sentinel sentinel;
    private Cluster cluster;
}

具体的配置项

spring:
  redis:
    host: 47. 104. 128. 12
    port: 6379
    password: 123456
  jedis:
    pool:
      max-active: 20
      max-idle: 10
      min-idle: 5

4.4 使用redis自动配置的默认的redisTemplate是使用jdk自带的序列化工具

通过redis客户端工具看到的key value是字节形式的,阅读起来不方便
在这里插入图片描述

我们如何修改redisTemplate的序列化工具,就是我们自己配置一个RedisTemplate

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>(); 
        //设置自己的序列化工具 
        template.setDefaultSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
}

5 整合Swagger2

5.1 Swagger2是什么?

它的出现就是为了方便进行测试后台的restful形式的接口,实现动态的更新,当我们在后台的接口修改了后,swagger可以实现自动的更新,而不需要人为的维护这个接口进行测试

5.2 为啥要用Swagger

程序员最喜欢什么? 最喜欢别人写文档
程序员最不喜欢什么? 最不喜欢自己写文旦

5.3 整合步骤

第一步:加入maven依赖

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.7.0</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.7.0</version>
</dependency>

5.4 加入swagger2的配置

@Configuration
public class Swagger2Config {
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.tuling.controller")) //你需要生成文档所在的包 .paths(PathSelectors.any())
                .build();
    }
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("springboot利用swagger构建api文档")//文档标题
                .description("简单优雅的restfun风格, http://blog.csdn.net/saytime") //描述 .termsOfServiceUrl("http://blog.csdn.net/saytime")
                .version("1.0")
                .build();
    }
}

5.5 在配置类上开启swagger2的文档

@SpringBootApplication
@EnableSwagger2
public class TulingvipSpringbootSwagger2Application {
}

5.6 使用示例:

/**
 * Created by Administrator on 2019/3/23.
 */
@RestController
@RequestMapping("/user")
@Api(value = "用户服务", description = "用户的基本操作")
public class UserController {
    @ApiOperation(value = "用户列表服务", notes = "查詢所有用戶的列表信息")
    @RequestMapping(value = "/list", method = RequestMethod.GET)
    public List<User> list() {
        List<User> userList = new ArrayList<>();
        for (String key : DataNode.users.keySet()) {
            userList.add(DataNode.users.get(key));
        }
        return userList;
    }

    @ApiOperation(value = "根据用户ID查询用户信息", notes = "根据url的id来获取用户详细信息")
    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "Integer", paramType = "path")
    @RequestMapping(value = "/findOneById/{userId}", method = RequestMethod.GET)
    public User findOneById(@PathVariable("userId") Integer userId) {
        for (String key : DataNode.users.keySet()) {
            User user = DataNode.users.get(key);
            if (user.getUserId() == userId) {
                return user;
            }
        }
        return null;
    }

    @ApiOperation(value = "根据用户名获取用户信息")
    @RequestMapping(value = "/findOneUserName/{userName}", method = RequestMethod.GET)
    public User findOneByName(@ApiParam(value = "用户名", type = "String") @PathVariable("userName") String userName) {
        for (String key : DataNode.users.keySet()) {
            User user = DataNode.users.get(key);
            if (user.getUserName().equals(userName)) {
                return user;
            }
        }
        return null;
    }

    @ApiOperation(value = "根据用户名获取用户信息")
    @ApiImplicitParams({@ApiImplicitParam(name = "id", value = "用户ID", required = true, dataType = "int", paramType = "query"), @ApiImplicitParam(name = "userName", value = "用户名称", required = true, dataType = "String", paramType = "query")})
    @RequestMapping(value = "/findOneByIdAndName", method = RequestMethod.GET)
    public User findOneByIdAndName(@RequestParam String userName, @RequestParam Integer id) {
        for (String key : DataNode.users.keySet()) {
            User user = DataNode.users.get(key);
            if (user.getUserName().equals(userName) && id == user.getUserId()) {
                return user;
            }
        }
        return null;
    }

    @ApiOperation(value = "根据查询条件获取用户信息")
    @RequestMapping(value = "/findOneByCondition", method = RequestMethod.GET)
    public User findOneByCondition(UserCondition userCondition) {
        for (String key : DataNode.users.keySet()) {
            User user = DataNode.users.get(key);
            if (user.getUserName().equals(userCondition.getUserName()) && user.getUserId() == userCondition.getUserId()) {
                return user;
            }
        }
        return null;
    }
}

@ApiModel(value = "用户实体")
public class User {
    public User(Integer userId, String userName, String password, String email, String birthDate) {
        this.userId = userId;
        this.userName = userName;
        this.password = password;
        this.email = email;
        this.birthDate = birthDate;
    }

    @ApiModelProperty(name = "用户id", dataType = "String", notes = "用户Id")
    private Integer userId;
    @ApiModelProperty(name = "用户名", dataType = "String", notes = "用户名")
    private String userName;
    @ApiModelProperty(name = "密码", dataType = "String", notes = "密码")
    private String password;
    @ApiModelProperty(name = "邮箱", dataType = "String", notes = "邮箱")
    private String email;
    @ApiModelProperty(name = "生日", dataType = "String", notes = "生日")
    private String birthDate;
}

5.7 访问地址

http://localhost:8080/swagger-ui.html
在这里插入图片描述

常用参数解析:

  • @Api()用于类;
    表示标识这个类是swagger的资源
  • @ApiOperation()用于方法;
    表示一个http请求的操作
  • @ApiParam()用于方法, 参数, 字段说明; 表示对参数的添加元数据 (说明或是否必填等)
  • @ApiModel()用于类
    表示对类进行说明, 用于参数用实体类接收
  • @ApiModelProperty()用于方法, 字段 表示对model属性的说明或者数据操作更改
  • @ApiIgnore()用于类, 方法, 方法参数 表示这个方法或者类被忽略
  • @ApiImplicitParam() 用于方法 表示单独的请求参数
  • @ApiImplicitParams() 用于方法, 包含多个 @ApiImplicitParam

6 整合rabbitmq

6.1 我们项目中为什么需要使用消息中间件?

①:异步
场景:用户注册后 , 把用户数据入库 , 然后向用户发送一封邮件 , 然后在发送一条短信
同步等待:150ms
在这里插入图片描述

异步发送:用户注册 , 把用户数据入库 , 然后通过异步任务分别执行发送邮件和短信

在这里插入图片描述

队列形式:用户注册数据入库同时 , 然后发送消息写入mq中 (由于写mq的时间很短 , 机会可以忽略不计)

在这里插入图片描述

②:解耦(用户下订单成功 , 然后发送一条减少库存的消息发送到mq中)
在这里插入图片描述

③:流量削峰
比如10W人来抢10个商品,在Mq中设置队列的长度为10,若队列长度超过10,那么后面的请求直接舍弃,从而来降低对DB的压力

在这里插入图片描述

6.2 rabbtimq的核心概念理解?

① Publisher(消息生产者)
消息的生产者,也是一个向交换器发布消息的客户端应用程序
② Message (消息对象)
消息,消息是不具名的,它由消息头和消息体组成。消息体是不透明的,而消息头则由一系列的可选属
性组成, 这些属性包括routing-key(路由键)、priority(相对于其他消息的优先权)、delivery-mode(指出该消息可能需要持久性存储)等
③ 交换器,用来接收生产者发送的消息并将这些消息路由给服务器中的队列。Exchange有4种类型:direct(默认),fanout(扇形交换机), topic(主题交换机), 和headers(不同交换机),不同类型的Exchange转发消息的策略有所区别
④ Queue
消息队列,用来保存消息直到发送给消费者。它是消息的容器,也是消息的终点。一个消息可投入一个或多个队列。消息一直在队列里面,等待消费者连接到这个队列将其取走。
⑤ Binding
绑定, 用于消息队列和交换器之间的关联。 一个绑定就是基于路由键将交换器和消息队列连 接起来的路由规则,所以可以将交换器理解成一个由绑定构成的路由表。Exchange和Queue的绑定可以是多对多的关系
⑥ Connection
网络连接, 比如一个TCP连接。
⑦ Channel
信道, 多路复用连接中的一条独立的双向数据流通道。 信道是建立在真实的TCP连接内的虚拟连接,AMQP命令都是通过信道发出去的,不管是发布消息、订阅队列还是接收消息, 这些动作都是通过信道完成。因为对于操作系统来说建立和销毁 TCP 都是非常昂贵的开销,所以引入了信道的概念, 以复用一条 TCP 连接。
⑧ Consumer
消息的消费者,表示一个从消息队列中取得消息的客户端应用程序。
⑨ Virtual Host
虚拟主机, 表示一批交换器、消息队列和相关对象。虚拟主机是共享相同的身份认证和加密环境的独立服务器域。每个 vhost 本质上就是一个 mini 版的 RabbitMQ 服务器, 拥有自己的队列、交换器、绑定和权限机制。vhost 是 AMQP 概念的基础, 必须在连接时指定, RabbitMQ 默认的 vhost 是 / 。
⑩ Broker
表示消息队列服务器实体
在这里插入图片描述

6.3 交换机的特性以及分类

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6.4 整合三板斧

①:导入maven依赖

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

②:查看自动配置以及对应的自动配置属性类

@Configuration
@ConditionalOnClass({RabbitTemplate.class, Channel.class})
@EnableConfigurationProperties(RabbitProperties.class)
@Import(RabbitAnnotationDrivenConfiguration.class)
public class RabbitAutoConfiguration {
    @Configuration
    @ConditionalOnMissingBean(ConnectionFactory.class)
    protected static class RabbitConnectionFactoryCreator {
        //rabbitmq 连接工厂
        @Bean
        public CachingConnectionFactory rabbitConnectionFactory(RabbitProperties properties, ObjectProvider<ConnectionNameStrategy> connectionNameStrategy) throws Exception {
            PropertyMapper map = PropertyMapper.get();
            //创建连接工厂
            CachingConnectionFactory factory = new CachingConnectionFactory(getRabbitConnectionFactoryBean(properties).getObject());
            //连接地址
            map.from(properties::determineAddresses).to(factory::setAddresses);
            //生产端的消息确认
            map.from(properties::isPublisherConfirms).to(factory::setPublisherConfirms);
            //不可路由消息的处理
            map.from(properties::isPublisherReturns).to(factory::setPublisherReturns);
            //配置通信管道
            RabbitProperties.Cache.Channel channel = properties.getCache().getChannel();
            map.from(channel::getSize).whenNonNull().to(factory::setChannelCacheSize);
            map.from(channel::getCheckoutTimeout).

                    whenNonNull().

                    as(Duration::toMillis).

                    to(factory::setChannelCheckoutTimeout);
            //配置管道缓存
            RabbitProperties.Cache.Connection connection = properties.getCache().getConnection();
            map.from(connection::getMode).whenNonNull().to(factory::setCacheMode);
            map.from(connection::getSize).whenNonNull().to(factory::setConnectionCacheSize);
            map.from(connectionNameStrategy::getIfUnique).whenNonNull().to(factory::setConnectionNameStrategy);
            return factory;
        }
    }

    @Configuration
    @Import(RabbitConnectionFactoryCreator.class)
    protected static class RabbitTemplateConfiguration {
        //模版配置类
        @Bean
        @ConditionalOnSingleCandidate(ConnectionFactory.class)
        @ConditionalOnMissingBean
        public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
            PropertyMapper map = PropertyMapper.get();
            RabbitTemplate template = new RabbitTemplate(connectionFactory);
            //配置消息转换器
            MessageConverter messageConverter = this.messageConverter.getIfUnique();
            if (messageConverter != null) {
                template.setMessageConverter(messageConverter);
            }//设置为true 那么不可达消息会交给RetrunConfirm处理,若设置为false 消息队列直接删除该消息
            template.setMandatory(determineMandatoryFlag());
            //配置模版属性
            RabbitProperties.Template properties = this.properties.getTemplate();
            if (properties.getRetry().isEnabled()) {
                template.setRetryTemplate(createRetryTemplate(properties.getRetry()));
            }
            //设置超时时间
            map.from(properties::getReceiveTimeout).whenNonNull().as(Duration::toMillis).to(template::setReceiveTimeout);
            //配置回复超时时间
            map.from(properties::getReplyTimeout).whenNonNull().as(Duration::toMillis).to(template::setReplyTimeout);
            //配置交换机
            map.from(properties::getExchange).to(template::setExchange);
            //配置路由key
            map.from(properties::getRoutingKey).to(template::setRoutingKey);
            return template;
        }

        private boolean determineMandatoryFlag() {
            Boolean mandatory = this.properties.getTemplate().getMandatory();
            return (mandatory != null) ? mandatory : this.properties.isPublisherReturns();
        }

        private RetryTemplate createRetryTemplate(RabbitProperties.Retry properties) {
            PropertyMapper map = PropertyMapper.get();
            RetryTemplate template = new RetryTemplate();
            SimpleRetryPolicy policy = new SimpleRetryPolicy();
            map.from(properties::getMaxAttempts).

                    to(policy::setMaxAttempts);
            template.setRetryPolicy(policy);
            ExponentialBackOffPolicy backOffPolicy = new ExponentialBackOffPolicy();
            map.from(properties::getInitialInterval).

                    whenNonNull().

                    as(Duration::toMillis).

                    to(backOffPolicy::setInitialInterval);
            map.from(properties::getMultiplier).

                    to(backOffPolicy::setMultiplier);
            map.from(properties::getMaxInterval).

                    whenNonNull().

                    as(Duration::toMillis).

                    to(backOffPolicy::setMaxInterval);
            template.setBackOffPolicy(backOffPolicy);
            return template;
        }

        @Bean
        @ConditionalOnSingleCandidate(ConnectionFactory.class)
        @ConditionalOnProperty(prefix = "spring.rabbitmq", name = "dynamic", matchIfMissing = true)
        @ConditionalOnMissingBean
        public AmqpAdmin amqpAdmin(ConnectionFactory connectionFactory) {
            return new RabbitAdmin(connectionFactory);
        }
    }

    @Configuration
    @ConditionalOnClass(RabbitMessagingTemplate.class)
    @ConditionalOnMissingBean(RabbitMessagingTemplate.class)
    @Import(RabbitTemplateConfiguration.class)
    protected static class MessagingTemplateConfiguration {
        @Bean
        @ConditionalOnSingleCandidate(RabbitTemplate.class)
        public RabbitMessagingTemplate rabbitMessagingTemplate(RabbitTemplate rabbitTemplate) {
            return new RabbitMessagingTemplate(rabbitTemplate);
        }
    }
}

③:在yml文件中 配置关键属性

public class RabbitProperties {
    /**
     * RabbitMQ host.
     */
    private String host = "localhost";
    /**
     * RabbitMQ port.
     */
    private int port = 5672;
    /**
     * Login user to authenticate to the broker.
     */
    private String username = "guest";
    /**
     * Login to authenticate against the broker.
     */
    private String password = "guest";
    /**
     * SSL configuration.
     */
    private final Ssl ssl = new Ssl();
    /**
     * Virtual host to use when connecting to the broker.
     */
    private String virtualHost;
    /**
     * Comma-separated list of addresses to which the client should connect.
     */
    private String addresses;
    /**
     * Requested heartbeat timeout; zero for none. If a duration suffix is not specified,
     * seconds will be used.
     */
    @DurationUnit(ChronoUnit.SECONDS)
    private Duration requestedHeartbeat;
    /**
     * Whether to enable publisher confirms.
     */
    private boolean publisherConfirms;
    /**
     * Whether to enable publisher returns.
     */
    private boolean publisherReturns;
    /**
     * Connection timeout. Set it to zero to wait forever.
     */
    private Duration connectionTimeout;
    /**
     * Cache configuration.
     */
    private final Cache cache = new Cache();
    /**
     * Listener container configuration.
     */
    private final Listener listener = new Listener();
    private final Template template = new Template();
    private List<Address> parsedAddresses;
}

#可配置常用属性

spring:
  rabbitmq:
    host: 47. 104. 128. 10
    port: 5672
    virtual-host: tulingvip-springboot-rabbitmq
    username: guest
    password: guest
    connection-timeout: 5000
    template:
      mandatory: true

7 springboot整合 actuator 监控管理

通过引入spring-boot-starter-actuator,可以使用Spring Boot为我们提供的准
生产环境下的应用监控和管理功能。我们可以通过HTTP,JMX,SSH协议来进
行操作,自动得到审计、 健康及指标信息等

7.1 监控访问路径前缀

management.endpoints.web.base-path=/actuator 这个是springboot监控默认的,我们可以修改
为自己的
在这里插入图片描述

management.endpoints.web.base-path=/tulingMonitor
在这里插入图片描述

总结 不管监控路径 是默认的还是 自己修改的, 为了安全起见,必须要通过spring security来控制访问
权限以免暴露你的服务信息

7.2 http 健康监控端点 默认只暴露了 health,info端点

在这里插入图片描述

①:通过 management.endpoints.web.exposure.include=* 来指定开放所有的端点
在这里插入图片描述

②:通过 management.endpoints.web.exposure.include=health,info,beans 通过逗号分开来指定 开放哪些端点

或者也可以通过 management.endpoint.具体端点.enabled=true|false 来开放或者打开哪些端点

7.3 具体端点分析

1)服务监控端点 http://localhost:8080//tulingMonitor/health
2)审计事件监控端点 http://localhost:8080//tulingMonitor/auditevents
3)服务装配bean的报告 端点: http://localhost:8080//tulingMonitor/beans
4)条件自动装配报告端点: http://localhost:8080//tulingMonitor/conditions
5)配置属性(配置前缀)端点 http://localhost:8080/tulingMonitor/configprops
6)服务环境端点 http://localhost:8080/tulingMonitor/env
7)应用 各个包 中的日志等级级别 端点 http://localhost:8080/tulingMonitor/loggers
8)应用堆栈端点 http://localhost:8080/tulingMonitor/heapdump 下载
9)线程dump端点监控 http://localhost:8080/tulingMonitor/threaddump
10)各项应用指标端点: http://localhost:8080/tulingMonitor/metrics
11)定时任务端点 http://localhost:8080/tulingMonitor/scheduledtasks
12)应用映射端点 http://localhost:8080/tulingMonitor/mappings
13)最新调用监控端点: http://localhost:8080/tulingMonitor/httptrace
14)自定义信息端点: http://localhost:8080/tulingMonitor/info

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lastinglate

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值