首页 文章 精选 留言 我的

精选列表

搜索[整合],共10000篇文章
优秀的个人博客,低调大师

第二篇:SpringBoot高级-整合redis作为缓存

Redis简介 Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 搭建Redis环境 1. 安装redis:使用Docker (使用docker中国加速 [root@localhost ~]# docker pull registry.docker-cn.com/library/redis Using default tag: latest latest: Pulling from library/redis 683abbb4ea60: Already exists 259238e792d8: Pull complete 78399601c709: Pull complete f397da474601: Pull complete c57de4edc390: Pull complete b2ea05c9d9a1: Pull complete Digest: sha256:5534b92530acc653f0721ebfa14f31bc718f68bf9070cbba25bb00bc7aacfabb Status: Downloaded newer image for registry.docker-cn.com/library/redis:latest 使用docker images查询 [root@localhost ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE registry.docker-cn.com/library/redis latest 71a81cb279e3 7 days ago 83.4MB mysql 5.7 66bc0f66b7af 7 days ago 372MB 使用docker启动redis [root@localhost ~]# docker run -d -p 6379:6379 --name myredis registry.docker-cn.com/library/redis ba65a5f3fc5c996ea23582a0cfeb0275be759c1a19fc920dd6f513127b5c9738 使用docker ps -a 查询运行情况 [root@localhost ~]# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ba65a5f3fc5c registry.docker-cn.com/library/redis "docker-entrypoint..." About a minute ago Up About a minute 0.0.0.0:6379->6379/tcp myredis 2. 引入redis依赖包 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 3. 配置redis # redis配置项 # Redis数据库索引(默认为0) spring.redis.database=0 # Redis服务器地址 spring.redis.host=192.168.43.53 # Redis服务器连接端口 spring.redis.port=6379 # Redis服务器连接密码(默认为空) spring.redis.password= 引入redis依赖包后系统就会自动引入RedisAutoConfiguration完成redis相关配置。其中就包括自动配置好了,RedisTemplate 、StringRedisTemplage。我们就可以在项目中直接使用。4. 编写redis测试方法 Redis 常见的五大数据类型: String(字符串)、List(列表)、Set(集合)、Hash(散列)/ ZSet(有序集合) stringRedisTemplate.opsForValue():【String(字符串)】 stringRedisTemplate.opsForList():【List(列表)】 stringRedisTemplate.opsForSet():【Set(集合)】 stringRedisTemplate.opsForHash():【Hash(散列)】 stringRedisTemplate.opsForZSet():【有序集合】 /** * Redis 常见的五大数据类型 * String(字符串)、List(列表)、Set(集合)、Hash(散列)/ ZSet(有序集合) */ @Autowired StringRedisTemplate stringRedisTemplate; @Autowired RedisTemplate redisTemplate; @Autowired RedisTemplate empRedisTemplate; // 自定义RedisTemplate @Test public void test01() { // 给redis存字符串数据 stringRedisTemplate.opsForValue().append("msg", "hello"); stringRedisTemplate.opsForList().leftPush("list", "v1"); stringRedisTemplate.opsForList().leftPush("list", "v2"); stringRedisTemplate.opsForList().leftPush("list", "v3"); stringRedisTemplate.opsForList().leftPush("list", "v4"); String msg = stringRedisTemplate.opsForValue().get("msg"); System.out.println(msg); // 给redis存对象数据 Employee employee = employeeMapper.getEmpById(1); // 这里使用默认的JDK序列化器:JdkSerializationRedisSerializer 将序列化后的数据保存到redis中 // 我们也可以自定义序列化器完成序列化存储 // 1. 自动手动将对象序列化为JSON字符串 // 2. 指定redisTemplate默认的序列化器 redisTemplate.opsForValue().set("emp", employee); empRedisTemplate.opsForValue().set("emp_json", employee); } 自定义序列化器: /** * Created by Administrator on 2018/7/4 0004. */ @Configuration public class MyRedisConfig { @Bean public RedisTemplate<Object, Employee> empRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Employee> template = new RedisTemplate<Object, Employee>(); template.setConnectionFactory(redisConnectionFactory); Jackson2JsonRedisSerializer<Employee> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Employee.class); template.setDefaultSerializer(jackson2JsonRedisSerializer); return template; } } 使用Redis测试SpringBoot缓存 原理:系统使用CacheManager(ConcurrentMapCacheManager默认)来创建Cache组件,来完成缓存的CRUD操作。 默认情况下系统使用SimpleCacheConfiguration来引入ConcurrentMapCacheManager缓存管理器--》ConcurrentMapCache作为缓存组件 引入了redis的starter后容器中保存的是RedisCacheManager--》RedisCache作为缓存组件(通过操作redis缓存数据), 默认保存数据 k-v 都是Object 默认利用jdk序列化保存 所以我们需要自定义CacheManager(使用我们自己的序列化器): 重写RedisCacheConfiguration类中的方法: @Bean public RedisCacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) { RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); cacheManager.setUsePrefix(true); List cacheNames = this.cacheProperties.getCacheNames(); if(!cacheNames.isEmpty()) { cacheManager.setCacheNames(cacheNames); } return (RedisCacheManager)this.customizerInvoker.customize(cacheManager); } @Configuration public class MyRedisConfig { @Bean public RedisTemplate<Object, Employee> empRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Employee> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); Jackson2JsonRedisSerializer<Employee> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Employee.class); template.setDefaultSerializer(jackson2JsonRedisSerializer); return template; } @Bean public RedisTemplate<Object, Department> deptRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException { RedisTemplate<Object, Department> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); Jackson2JsonRedisSerializer<Department> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Department.class); template.setDefaultSerializer(jackson2JsonRedisSerializer); return template; } @Bean public RedisCacheManager empCacheManager(RedisTemplate<Object, Employee> empRedisTemplate) { RedisCacheManager cacheManager = new RedisCacheManager(empRedisTemplate); // 使用前綴,默认使用cacheNames作为前缀 cacheManager.setUsePrefix(true); return cacheManager; } @Bean public RedisCacheManager deptCacheManager(RedisTemplate<Object, Department> deptRedisTemplate) { RedisCacheManager cacheManager = new RedisCacheManager(deptRedisTemplate); // 使用前綴,默认使用cacheNames作为前缀 cacheManager.setUsePrefix(true); return cacheManager; } @Primary @Bean public RedisCacheManager cacheManager(RedisTemplate<Object, Object> redisTemplate) { RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); cacheManager.setUsePrefix(true); return cacheManager; } } 在使用RedisCache时使用注解指定CacheManager: @Cacheable(cacheNames = {"emp"}, cacheManager = "empCacheManager") @Service public class EmployeeService { 手动编码操作缓存: @Autowired @Qualifier("empCacheManager") CacheManager empCacheManager; public Employee getEmp(Integer id){ Employee emp = employeeMapper.getEmpById(id); // 获取某个缓存组件 Cache empCache = empCacheManager.getCache("emp"); empCache.put("emp:1", emp); return emp; }

优秀的个人博客,低调大师

spring cloud 微服务日志跟踪 sleuth logback elk 整合

看过我之前的文章的就可以一步一步搭建起日志传输到搜索引擎 不知道的 看下之前的文章 (1)记一次logback传输日志到logstash根据自定义设置动态创建ElasticSearch索引 (2)关于” 记一次logback传输日志到logstash根据自定义设置动态创建ElasticSearch索引” 这篇博客相关的优化采坑记录 (3)日志收集(ElasticSearch)串联查询 MDC 这里我们结合sleuth 可以降服务之间的调用使用唯一标识串联起来已达到我们通过一个标识可以查看所有跨服务调用的串联日志,与上一篇 的MDC不同 sleuth 简单原理说下 就是在最初发起调用者的时候在请求头head中添加唯一标识传递到直接调用的服务上面 然后之后的服务做类似的操作 好了 不多比比了 上代码 首先所有的服务或spring boot项目

优秀的个人博客,低调大师

SpringBoot 整合 oauth2(五)实现 jwt 及 扩展

什么是jwt,即 json web token。JWT是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。也是一种token,但是和token有一些不同。 jwt优点: 自包含 防篡改 可自定义扩展 JWT的结构 JWT包含了使用.分割的三部分: Header 头部 Payload 负载 Signature 签名 比如:eyJpc3MiOiJKb2huIFd1IEpXVCIsImlhdCI6MTQ0MTU5MzUwMiwiZXhwIjoxNDQxNTk0NzIyLCJhdWQiOiJ3d3cuZXhhbXBsZS5jb20iLCJzdWIiOiJqcm9ja2V0QGV4YW1wbGUuY29tIiwiZnJvbV91c2VyIjoiQiIsInRhcmdldF91c2VyIjoiQSJ9 三个新东西 什么是自包含? 字符串里包含用户信息。 什么是防篡改? 签名用于验证消息的发送者以及消息是没有经过篡改的。 可扩展是什么意思? 你可以在Payload部分加入自己想加入的json字符串 那我们既然token的实现方式那么优秀,为什么还要有jwt呢,这就需要了解他们的生成机制。 token生成的其实就是一个UUID,和业务没有丝毫的关系,这样带来最大的问题,就是需要人工持久化处理token(像处理分布式下的sessionId一样)。但是jwt就不需要,因为自包含,所以token里有身份验证信息,不需要做后台持久化处理,前端每次请求被保护的资源时请求头里带上该token就可以实现。 好了开始正文。 本文建立在第三节的基础上。这里是顺风车 1. 新增JwtTokenConfig @Configuration public class JwtTokenConfig{ @Bean public TokenStore jwtTokenStore(){ return new JwtTokenStore(jwtAccessTokenConverter()); } /** * token生成处理:指定签名 */ @Bean public JwtAccessTokenConverter jwtAccessTokenConverter(){ JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter(); accessTokenConverter.setSigningKey("internet_plus"); return accessTokenConverter; } } jwtTokenStore方法返回一个TokenStore对象的子对象JwtTokenStore,供给认证服务器取来给授权服务器端点配置器,通俗点就是让MyAuthorizationServerConfig能注入到值。 jwtAccessTokenConverter方法是根据签名生成JwtToken,同样也需要在MyAuthorizationServerConfig类里注入。 修改MyAuthorizationServerConfig 的 configure方法 /** * 认证服务器 * Created by Fant.J. */ @Configuration @EnableAuthorizationServer public class MyAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; @Autowired private TokenStore tokenStore; @Autowired private JwtAccessTokenConverter jwtAccessTokenConverter; @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { super.configure(security); } /** * 客户端配置(给谁发令牌) * @param clients * @throws Exception */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory().withClient(ConsParams.Auth.GET_CLIENT_ID) .secret(ConsParams.Auth.GET_SECRET) //有效时间 2小时 .accessTokenValiditySeconds(ConsParams.Auth.GET_TOKEN_VALIDITY_SECONDS) //密码授权模式和刷新令牌 .authorizedGrantTypes(ConsParams.Auth.GE_TAUTHORIZED_GRANT_TYPES) .scopes(ConsParams.Auth.GE_TSCOPES); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenStore(tokenStore) .authenticationManager(authenticationManager) .userDetailsService(userDetailsService) .accessTokenConverter(jwtAccessTokenConverter); } } } 和第三节不同的是 endpoints添加了accessTokenConverter属性,它规定了token生成器是jwtAccessTokenConverter,并按照我们设置的签名来生成。 启动项目 给/oauth/token 发送post请求获取token 请求头:Authorization:Basic +clientid:secret 的base64加密字符串 (认证服务器中设置的client信息) 请求参数:username password (用户登陆账号密码) 2. JWT扩展 在前文我们介绍过jwt的可扩展性,一般情况下实现jwt就可以了,但是有一些特殊需求,比如你想在返回的token中附带一些别的信息,这就需要我们对jwt进行扩展。 2.1 修改JwtTokenConfig 新增jwtTokenEnhancer方法 @Configuration public class JwtTokenConfig{ @Bean public TokenStore jwtTokenStore(){ return new JwtTokenStore(jwtAccessTokenConverter()); } /** * token生成处理:指定签名 */ @Bean public JwtAccessTokenConverter jwtAccessTokenConverter(){ JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter(); accessTokenConverter.setSigningKey("internet_plus"); return accessTokenConverter; } @Bean public TokenEnhancer jwtTokenEnhancer(){ return new JwtTokenEnhancer(); } } jwtTokenEnhancer方法 返回一个JwtTokenEnhancer并交给bean工厂。 2.2 增加JwtTokenEnhancer类 /** * Jwt token 扩展 * Created by Fant.J. */ public class JwtTokenEnhancer implements TokenEnhancer { @Override public OAuth2AccessToken enhance(OAuth2AccessToken oAuth2AccessToken, OAuth2Authentication oAuth2Authentication) { Map<String,Object> info = new HashMap<>(); info.put("provider","Fant.J"); //设置附加信息 ((DefaultOAuth2AccessToken)oAuth2AccessToken).setAdditionalInformation(info); return oAuth2AccessToken; } } 重写TokenEnhancer的enhance方法,根据需求扩展jwt。 2.3 修改MyAuthorizationServerConfig类 /** * 认证服务器 * Created by Fant.J. */ @Configuration @EnableAuthorizationServer public class MyAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; @Autowired private TokenStore tokenStore; @Autowired private JwtAccessTokenConverter jwtAccessTokenConverter; @Autowired private TokenEnhancer jwtTokenEnhancer; @Override public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { super.configure(security); } /** * 客户端配置(给谁发令牌) * @param clients * @throws Exception */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory().withClient(ConsParams.Auth.GET_CLIENT_ID) .secret(ConsParams.Auth.GET_SECRET) //有效时间 2小时 .accessTokenValiditySeconds(ConsParams.Auth.GET_TOKEN_VALIDITY_SECONDS) //密码授权模式和刷新令牌 .authorizedGrantTypes(ConsParams.Auth.GE_TAUTHORIZED_GRANT_TYPES) .scopes(ConsParams.Auth.GE_TSCOPES); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenStore(tokenStore) .authenticationManager(authenticationManager) .userDetailsService(userDetailsService); TokenEnhancerChain enhancerChain = new TokenEnhancerChain(); List<TokenEnhancer> enhancerList = new ArrayList<>(); enhancerList.add(jwtTokenEnhancer); enhancerList.add(jwtAccessTokenConverter); enhancerChain.setTokenEnhancers(enhancerList); endpoints .tokenEnhancer(enhancerChain) .accessTokenConverter(jwtAccessTokenConverter); } } endpoints的tokenEnhancer方法需要我们提供一个token增强器链对象TokenEnhancerChain,所以我们需要在链中加入我们重写的TokenEnhancer和jwtAccessTokenConverter,然后放入endpoints。 启动项目 和上文获取token方式相同。 下图红框便是我添加的扩展。 解析jwt,获取扩展信息 如果我们需要获取jwt本来就有的信息,我们直接请求方法中吧Authentication当做参数,就可以获取到jwt原始信息。 如果我们需要获取jwt扩展的信息,即我们自定义添加的信息,我们需要做这几个操作: pom导入依赖 <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.7.0</version> </dependency> UserController.java @GetMapping("/me") public ServerResponse getCurrentUser(Authentication user, HttpServletRequest request) throws UnsupportedEncodingException { String s = user.getPrincipal().toString(); String name = user.getName(); String header = request.getHeader("Authorization"); String token = StringUtils.substringAfter(header,"bearer "); Claims body = Jwts.parser().setSigningKey(ConsParams.Auth.GET_SIGNING_KEY.getBytes("UTF-8")) .parseClaimsJws(token).getBody(); String username = (String) body.get("username"); log.info("解析token获取到的username为{}",username); log.info("从Authentication里获取到的username为{}",s); log.info("从Authentication里获取到的username为{}",name); return ServerResponse.createBySuccess(user); } 介绍下我的所有文集: 流行框架 SpringCloudspringbootnginxredis 底层实现原理: Java NIO教程Java reflection 反射详解Java并发学习笔录Java Servlet教程jdbc组件详解Java NIO教程Java语言/版本 研究

优秀的个人博客,低调大师

SpringBoot开发案例之整合Kafka实现消息队列

前言 最近在做一款秒杀的案例,涉及到了同步锁、数据库锁、分布式锁、进程内队列以及分布式消息队列,这里对SpringBoot集成Kafka实现消息队列做一个简单的记录。 Kafka简介 Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。 对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka的目的是通过Hadoop的并行加载机制来统一线上和离线的消息处理,也是为了通过集群来提供实时的消息。 Kafka是一种高吞吐量的分布式发布订阅消息系统,有如下特性: 通过O(1)的磁盘数据结构提供消息的持久化,这种结构对于即使数以TB的消息存储也能够保持长时间的稳定性能。 高吞吐量:即使是非常普通的硬件Kafka也可以支持每秒数百万的消息。 支持通过Kafka服务器和消费机集群来分区消息。 支持Hadoop并行数据加载。 术语介绍 Broker Kafka集群包含一个或多个服务器,这种服务器被称为broker Topic每条发布到Kafka集群的消息都有一个类别,这个类别被称为Topic。(物理上不同Topic的消息分开存储,逻辑上一个Topic的消息虽然保存于一个或多个broker上但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处) PartitionPartition是物理上的概念,每个Topic包含一个或多个Partition. Producer负责发布消息到Kafka broker Consumer消息消费者,向Kafka broker读取消息的客户端。 Consumer Group每个Consumer属于一个特定的Consumer Group(可为每个Consumer指定group name,若不指定group name则属于默认的group)。 Kafka安装 Kafka需要依赖JAVA环境运行,如何安装JDK这里不做介绍。 下载kafka: wget http://mirror.bit.edu.cn/apache/kafka/1.1.0/kafka_2.11-1.1.0.tgz 将包下载到执行目录并解压: cd /usr/local/ tar -xcvf kafka_2.11-0.10.0.1.tgz 修改kafka配置文件: cd kafka_2.11-0.10.0.1/config/ #编辑配置文件 vi server.properties broker.id=0 #端口号、记得开启端口,云服务器要开放安全组 port=9092 #服务器IP地址,修改为自己的服务器IP host.name=127.0.0.1 #zookeeper地址和端口, Kafka支持内置的Zookeeper和引用外部的Zookeeper zookeeper.connect=localhost:2181 分别启动 kafka 和 zookeeper: ./zookeeper-server-start.sh /usr/local/kafka_2.11-0.10.0.1/config/zookeeper.properties & ./kafka-server-start.sh /usr/local/kafka_2.11-0.10.0.1/config/server.properties & SpringBoot集成 pom.xml引入: <!--kafka支持--> <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> <version>1.3.5.RELEASE</version><!--$NO-MVN-MAN-VER$--> </dependency> application.properties配置: #kafka相关配置 spring.kafka.bootstrap-servers=192.168.1.180:9092 #设置一个默认组 spring.kafka.consumer.group-id=0 #key-value序列化反序列化 spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer spring.kafka.consumer.value-deserializer=org.apache.kafka.common.serialization.StringDeserializer spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer spring.kafka.producer.value-serializer=org.apache.kafka.common.serialization.StringSerializer #每次批量发送消息的数量 spring.kafka.producer.batch-size=65536 spring.kafka.producer.buffer-memory=524288 生产者KafkaSender: /** * 生产者 * @author 科帮网 By https://blog.52itstyle.com */ @Component public class KafkaSender { @Autowired private KafkaTemplate<String,String> kafkaTemplate; /** * 发送消息到kafka */ public void sendChannelMess(String channel, String message){ kafkaTemplate.send(channel,message); } } 消费者: /** * 消费者 spring-kafka 2.0 + 依赖JDK8 * @author 科帮网 By https://blog.52itstyle.com */ @Component public class KafkaConsumer { /** * 监听seckill主题,有消息就读取 * @param message */ @KafkaListener(topics = {"seckill"}) public void receiveMessage(String message){ //收到通道的消息之后执行秒杀操作 } } 码云下载:从0到1构建分布式秒杀系统 参考 http://kafka.apache.org/ 作者: 小柒2012 欢迎关注: https://blog.52itstyle.com

优秀的个人博客,低调大师

SpringBoot 整合 oauth2(四)实现 token 持久化

为什么需要给token做持久化,试想如果存储token的服务器宕机后,用户信息也会伴随着失效,用户需要重新登陆来获取token,难免降低了用户体验,所以我们需要像处理session分布式一样,将token持久化。 我的案例是将token存储到redis里。 其实springboot已经帮我们封装了太多的东西了,在上一章的基础上,我们只需要添加不到10行代码,就可以实现redis的持久化。 1. 新增 TokenStoreConfig.java /** * 把token存到redis * Created by Fant.J. */ @Configuration public class TokenStoreConfig { @Autowired private RedisConnectionFactory redisConnectionFactory; @Bean public TokenStore redisTokenStore(){ return new RedisTokenStore(redisConnectionFactory); } } 2. 新增 application.properties spring.redis.database=0 # Redis服务器地址 spring.redis.host=47.xx4.xx9.xx # Redis服务器连接端口 spring.redis.port=6379 # Redis服务器连接密码(默认为空) spring.redis.password=root # 连接池最大连接数(使用负值表示没有限制) spring.redis.pool.max-active=8 # 连接池最大阻塞等待时间(使用负值表示没有限制) spring.redis.pool.max-wait=-1 # 连接池中的最大空闲连接 spring.redis.pool.max-idle=8 # 连接池中的最小空闲连接 spring.redis.pool.min-idle=0 # 连接超时时间(毫秒) spring.redis.timeout=0 3. 修改 MyAuthorizationServerConfig.java //新增一个注入 @Autowired private TokenStore tokenStore; @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints .tokenStore(tokenStore) //新增这一行 .authenticationManager(authenticationManager) .userDetailsService(userDetailsService); } 好了,token在redis里面的存储就完成了。这么简单的吗?对,就是这么简单,因为springboot包装的很好了,如果检测到认证服务,它会先从tokenStore获取对应的token数据,如果tokenStore没有,则新生成一个token并存入redis。 拓展 那redis是怎么连接的呢? 我们在第一个类中注入了RedisConnectionFactory 这个工厂,它是个接口,里面包含了关于redis连接的方法。只要你按照spring提供的默认配置属性来配置redis,成功连接是没有问题的。贴一小段连接核心源码证明一下 public RedisConnection getConnection() { if (cluster != null) { return getClusterConnection(); } Jedis jedis = fetchJedisConnector(); JedisConnection connection = (usePool ? new JedisConnection(jedis, pool, dbIndex, clientName) : new JedisConnection(jedis, null, dbIndex, clientName)); connection.setConvertPipelineAndTxResults(convertPipelineAndTxResults); return postProcessConnection(connection); } 这是RedisConnectionFactory子类工厂JedisConnectionFactory中的getConnection方法。 redis属性如何拿到的呢? package org.springframework.boot.autoconfigure.data.redis; import java.util.List; import org.springframework.boot.context.properties.ConfigurationProperties; @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 int timeout; private RedisProperties.Pool pool; private RedisProperties.Sentinel sentinel; private RedisProperties.Cluster cluster; public RedisProperties() { } 上面是springboot获取属性配置文件的操作。 ( 顺便也带给大家一个获取application.properties 属性的一个规范的方法。) 中间的装配连接池啥的就不在这说了,有兴趣的可以跟踪源码去看看大世界(不得不称赞springboot的源码写的真是碉堡了,简单粗暴Future 和 Callback用的也是流弊的很)。所以还得自己去看去琢磨。 介绍下我的所有文集: 流行框架 SpringCloudspringbootnginxredis 底层实现原理: Java NIO教程Java reflection 反射详解Java并发学习笔录Java Servlet教程jdbc组件详解Java NIO教程Java语言/版本 研究

优秀的个人博客,低调大师

从威胁到整合,容器将改变openstack的未来?

分享嘉宾简介:九州云99Cloud副总裁陈沙克,多年深耕于开源云计算平台Openstack技术,目前主要负责九州云99Cloud的产品、社区和研发。 从2010年发布到现在,就IaaS层面在目前的开源领域,Openstack已然成为一个代名词。在这期间,Openstack也曾因为种种原因发生过一些调整和改变,而容器的出现,也对Openstack造成了革命性的影响。 一、OpenStack 重要发展历程 在2013年基金会成立的时候, Rackspace将OpenStack的控制权交给基金会负责,OpenStack把自己定位为一个“可以做私有云、公有云的平台”。 当Docker出来时,Openstack已然经过两年的磨练,也考虑到市场环境因素,将定位调整为一款“管理引擎”,可以管理虚拟化、物理机、虚拟机、容器等等存储网络。就目前来讲,它被赋予的使命非常多,但同时也饱受Docker的威胁。而且由于Openstack什么都要管,它的功能模块非常多,基本上每个模块都要实现一个功能,目前除了基本功能以外,已有三四十个大项目,每个大项目下面还有好几个子项目。所以如果去GitHup上浏览,会发现Openstack的项目列表里面包含有几百个项目。实际上,对用户有用的或者说跟用户实际功能相关的项目数量,大概在三四十个左右。 在2015年,Openstack 引入了“大帐篷”策略。这个策略是指先定义出来一些必须用到的核心模块,像Nova、Glance、Swift这些,剩下的再根据用户实际需求选用。采用大帐篷策略以后,项目爆长,为了应对用户对虚拟机、容器、物理机等等上面的需求,Openstack变得越来越复杂。 二、OpenStack搭建流程 对企业来说,要将Openstack引入,首先要准备硬件,把存储准备好,然后要装操作系统。目前很多厂商已经对安装操作系统那一块做了自动化,减轻用户部署的痛苦。再就是安装Openstack的各种服务,配置Openstack各个节点的高可用。 安装完这些还不够,还需配置整个平台,做日志的收集和监控。后续还需要对整个Openstack平台进行运维和升级。下图基本上就是企业在引入Openstack的时候,必须要做的一些过程。 三、OpenStack的痛点和难点 1、安装和部署困难 在安装Openstack的时候,可能自己在测试的时候都很顺,但在实际的企业环境中就会面对各种的挑战。比如,国内有很多企业是完全是不能联网的,怎么在网络不通的情况下完成安装部署?实际上非常具有挑战。而且有的企业在联网情况下安装完可以很好的运行,一旦网络不好或者断网,效率可能变得很低。这些问题如果没有在实际安装过程中亲身经历过,很难提前想象。 2、维护更加困难 当Openstack节点数量大的时候,靠传统的人工维护方式是非常麻烦的。在几十个节点上面,如果想要去查看日志或者修改配置,都是很难做的事情。 3、升级难上加难 Openstack进入企业面临最大的挑战,就是升级。2016年是国内企业采纳Openstack最多的一年,也是发展最好的一年,但同时升级的问题也被不断提出。当企业有了新功能、新特性,希望升级的时候,会面临这样一个问题: 以往软件升级都是采用发行版、安装包的方式实现,像红帽采用的Yum,乌班图的 apt-get 。但Openstack不行,因为Openstack现在一年两个版本,中间只有半年的时间,厂商要对其进行打包和测试,加上Openstack现在的组件有几十个那么多,厂商根本无法在那么短的时间内完成那么多的工作。而且当某次升级你没跟上,时间就会越拖越长。 在之前,很多厂商都只能通过手动操作熬夜通宵来给企业升级,因为只有这种办法才能完成。Openstack可以在不宕机、影响很小的情况下完成升级,但是这个过程是很长很累的,需要手动一点点地更新,而且每个客户的情况都不太一样,只能区别对待。而且不同的版本需要处理的问题是不一样的,经验的积累也是不一样的。所以,对厂商来说,升级是件很痛苦的事。 四、容器给Openstack带来新突破 那么,究竟要怎么帮助企业去解决这个问题呢? 可以说,在容器出现之前,这个问题是无解的。容器出现后,看到了希望,把Openstack放在容器里面进行升级。接触过容器的应该知道,在容器里面没有安装的过程,它已经提前把安装文件录入到file里面。只需将Docker放到相应的机器上面,启动起来,再把配置文件放回去,就可以把Openstack装起来。这样,整个过程能减少很多问题。至少,之前很容易遇到的语言冲突、包冲突的问题可以解决掉。 而且,随着容器化的使用,厂商的配置管理也启用了专门的工具。在Openstack升级上有个很大的问题,就是升级导致的冲突问题,这个非常不好解决,解决起来也没有任何的意义,完全是拼体力。但用Docker隔开以后,已经可以完全避免这个问题了。还有之前当操作系统跟Openstack不是同一个语言的时候,也很容易导致它的依赖关系有冲突,解决起来不但没有任何意义,还没完没了,容器化后同样能进行规避。 更多好处可以参考"容器化 OpenStack 的10个好处"一文。试想,把Openstack容器化,整个安装过程(不包括安装操作系统)可能只需要20分钟。在生产环境中,装20分钟和装2个小时甚至一天的区别并不太大,但是在开发测试和验证环境里面,20分钟和2个小时存在很大差异。Openstack里面有许多功能需要反复的测试和操作,当时间减少至20分钟的时候,将带来极大的好处。 五、Openstack容器化的成熟项目——Kolla 对于Openstack的厂商来说,都曾体会过前面提到的痛点和难点,所以也都在很积极地解决这些问题。Rackspace、乌班图的Canonical、 TCB Cloud 、Mirantis都做了相应的解决办法去推动容器化,只是做法各有差异。除了厂商,社区也在努力,Kolla就是Openstack社区里推出的一个专门做Openstack容器化的项目。 目前来说,Kolla已经非常成熟,可以投入使用。Kolla不仅仅是把Openstack的组件容器化,还把周围的所有的组件也容器化。简单点说,一台机器如果把容器删掉,那么这台机器将不会有任何剩留。因为它做得非常彻底,把所有的东西都放在了容器里面。这样做的好处也显而易见,这台机器不管做什么东西,迭代都会非常快。 Kolla之所以能迅速成熟是因为它有个理念——“怎么简单怎么来”。它可以通过源码或发行版的RTM发安装包完成安装,也能通过镜像去配置文件,再放到相应的节点上去完成配置。当然,这个非常理想的状况,因为在实际部署中,会面临很多的东西。 没有用过Kolla,或对Docker不是很熟悉的,只要了解Docker的理念,就会发现这种方式非常理想化,只需要在这台机器以前的Docker file或master文件里面,不断在相应的节点上放进去你想要达到的目标,启动起来就可以了。这种灵活性也的确能给实际操作带来很多好处。 下图是Kolla的工作流程。一个Docker装Openstack,Openstack在容器里跑。Docker在现在的企业使用中会遇到很多挑战性的问题,比如说安全的问题,比如说网络性能的问题。但是,Kolla的使用没有面临性能的问题,也没有面临安全的问题,因为它是内部的使用Docker,它的网络直接是通过网桥出去的,就没有网络、性能的问题。所以说,Kolla利用了Docker非常稳定的部分,帮助Openstack实现了容器化。 目前来说,容器化给Openstack带来了许多革命性的变化。未来有一种趋势,它会自己容器化,也会管理容器,会用容器给用户提供一些终端的服务。从今年的发展趋势也能看到,未来很多东西会通过容器来启动,Openstack上面有很多的服务,以前都是要很重地往里面装一些东西,以后则可以直接放入Docker file启动。下面列了几个Openstack里面容器相关的项目,到目前来讲,Kolla是最成熟的,剩下的几个也都在发展中。 本文作者:佚名 来源:51CTO

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册