首页 文章 精选 留言 我的

精选列表

搜索[整合],共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语言/版本 研究

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

eBay宣布拥抱容器,将全面整合Kubernetes和OpenStack

在线拍卖及购物网站eBay比亚马逊(Amazon)成立晚一年,但却比Google、Facebook等众多的巨无霸要早。和其他的伙伴们一样,eBay也为大量的用户提供服务,它在190个国家拥有1.59亿活跃买家而且支撑了超过8亿条商品信息。要支持海量用户并非易事,这需要持续扩展基础架构,所以eBay一直在积极地拥抱新技术。 为了管理云端基础架构,eBay在三年前把虚拟机从VMware的ESXi Hypervisor切换到了OpenStack之上的KVM,因而成为OpenStack的早期忠实用户(eBay使用他们自行部署的OpenStack,做了大量的定制化开发)。该公司从大约300台运行“Essex(艾塞克斯)”版本OpenStack的服务器起步,很快在三年后eBay和PayPal就共同运行在“Havana(哈瓦那)”版本上,超过30万个核、支持了超过1万2千个KVM hypervisor、通过Open vSwitch虚拟交换机横跨了十多个可用性区域(Availability Zone)而且为了公司多个业务部门的需要配置了超过15个虚拟私有云。 现在,eBay开始在前端使用由Google开源的Kubernetes容器调度系统,而且eBay计划把它与OpenStack结合在一起来管理容器化的应用程序。 eBay是世界顶级零售商品牌之一,它的规模不能和诸如Google、Amazon、微软和Facebook这类的超级巨无霸相比。但是,它的基础架构也非常大,而且该公司非常重视基础架构,包括使用集装箱式的数据中心、用燃料电池供电、使用惠普和戴尔的hyperscale(超大规模)级别的主机而且经常使用定制化的超强处理器。(我们听说,eBay喜欢让它的处理器运行时温度高一点儿来获得更高的系统性能,但eBay却没回应过这个传言)。 eBay云计算技术服务团队的资深成员Ashwin Raveendran本周在KubeCon 2015会议上说他们正在尝试使用Kubernetes容器调度器来增强他们的OpenStack云。eBay是第一个愿意把OpenStack和Kubernetes结合的大型IT企业。Raveendran说eBay(在七月已经同PayPal支付服务进行了拆分)还在继续扩展它的基础架构而且当前在超过15万台服务器上使用了50多万个核。一个更直观的说法就是,这使得eBay的服务器集群规模已经同Rackspace Hosting及Softlayer这类的公有云服务提供者一样 。 在eBay一个典型的可用性区域拥有5000到20000台服务器,而且服务器会被分配到500个节点的chunk中。有意思的是,根据eBay在过去公布的一些数据,在2013年(在它剥离PayPal之前)它的CPU核数呈现为线性地增长而VM以及部署在其基础架构上的项目的数量则是指数级增长。关于存储,我们猜想eBay拥有超过200PB的容量,它应该运行在相当多的服务器之上。截止今年春天,1.6PB用于Cinder块存储。大约120PB的存储用于支持Hadoop,这也使其成为世界上最大的分析平台之一。 Raveendran在eBay所就职的数据及基础架构服务部门每秒钟从应用程序和基础架构监控系统中抽取2百万个指标(metrics),而且每天生成300TB以上的日志文件因为它每天需要处理十亿次查询并且显示200亿以上的图片。它显然是一个庞大且复杂的操作,而我们简化了一点儿。 eBay的平台栈看起来和大多数的现代企业在概念上很类似。 OpenStack统一管理服务器和存储,并抽象出计算、存储和网络等资源。当前,eBay的现有系统强制每一个应用程序实例运行在它自己专用的虚拟机中。eBay使用Kubernetes不仅仅是改为用容器来部署应用程序,而是在该公司以基础架构的云计算层为中心来改变应用程序的生命周期 (包括构建、部署、监控并且修复问等开发者和系统管理员需要执行的关键功能)。eBay计划以容器作为运行环境而Kubernetes在OpenStack之上来管理这些容器来实现更佳灵活的部署模型。eBay所采用的Kubernetes使用方式是受到了他们当前在虚拟机里部署应用程序的自主技术的启发。 当前的设置如图所示: 目前,eBay的大多数程序是用Java开发的。而且和很多基于虚拟机的商业集群一样,eBay的集群也是以静态的方式来调度的。严格地讲,这种方式意味着基础架构云中的服务器节点被分配到每一类负载中,就像这样: 在集群中静态地调度节点显然不是一个理想的状态,但是很多公司在部分应用程序存在很大峰值的情况下也同样在其私有云中静态地分配容量。“这些服务对于相应的私有云而言是很大的问题,而且当我们需要容量的时候也不能迅速扩展到公有云上去“,Raveendran解释到。“我们不得不最大化地利用我们的资源”。 (除非你能创建和Amazon类似的自己拥有的公有云,当然我们跑题了)。 但是为什么诸如Kubernetes和Mesosphere等技术越来越受关注的原因之一是当多个负载共享一台主机时他们对于服务器的开销要小得多,而且可能更重要的是运行扩展负载的容器相比于传统的服务器虚拟化能够以一种快得多的方式启动和终止。曾经老旧的软件容器技术又焕发了新生,而且现在对于那些在过去的十年里使用相当重的技术来进行服务器虚拟化的企业而言很有诱惑力。他们现在开始明白什么时候坚固异常的虚拟机隔离手段并不必要而什么时候容器就可以满足需求了。 eBay主动拥抱了容器,但也需要继续在其基础架构云中支持虚拟机,因此它计划使用OpenStack的Magnum插件,请看五月的文章了解该平台的信息,它是用来将Docker Swarm和Kubernetes容器调度器引入OpenStack。 如你所见,eBay将用Kubernetes加入Docker容器运行环境的kubelet主机代理进程替代其自主的主机代理进程。应用程序将从一个容器仓库下载并被部署到Kubernetes pod中的一台服务器,而且pod中的所有服务器在需要时可以被共同地管理。这个配置也将在eBay当前的基础架构中淘汰静态的负载均衡器和防火墙,Raveeddran称之为基础架构运维中的一个大瓶颈。当这些都完成了,动态调度看起来就是这样的: Raveendran解释说是Kubernetes能够吸引eBay关注的原因就是因为它是开源软件,有很多人在一起协作而且eBay可以有所贡献也能从中受益。可能更重要的, 在多个运行Docker容器的公有云上Kubernetes可以用于控制器层,这使得eBay在需求发起时有能力扩展到公有云而且工作负载能够从eBay的分布式私有云迁移到一个公有云中。 Raveendran说,转向Docker容器和Kubernetes来控制工作负载并不是没有挑战。如很多人多年来抱怨的,网络是OpenStack的一个挑战,特别是当前的现实问题是OpenStack并没有一个同Amazon Web服务(AWS)和Google计算引擎(Google Compute Engine)类似的虚拟路由器。但这里是eBay对于如何解决它的思考: 其想法是使用OpenStack的Neutron网络插件来创建一个Kubernetes路由器。Raveendran说在经历了一个漫长的过程后,eBay只是将用于网络三层所有路径的边界网关协议(BGP)下放到服务器主机而非仅仅停留在基础架构中的机柜顶部交换机(TOR)上。这些是eBay的巨无霸伙伴们为了简化网络已经完成的事情,它使得一个单一网络囊括了差不多10万台设备(有时会更多)。 eBay担心的另一件事是规模,当然他们正在和Kubernetes社区一起提升Kubernetes的性能。Kubernetes早期发布版本中有一些自行设定的限制,因为Google和他的社区伙伴们试图使得语法和基础适用于混合的负载以及不同于Google内部规范的硬件环境。eBay正在努力构建自己的Kubernetes集群并使用Kubernetes来抽象容器层以便于实现跨数据中心region或者私有云和公有云混合体的扩展。另外,eBay也在尝试一种方式把它的Cinder块存储与Kubernetes容器pods相结合。 本文作者:李毅 来源:51CTO

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

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

Nacos

Nacos

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

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册