Android NFC标签 开发深度解析 触碰的艺术

Posted 一叶知秋V

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android NFC标签 开发深度解析 触碰的艺术相关的知识,希望对你有一定的参考价值。

Jedis 是一个基于 Java 语言的 Redis 客户端,本文主要介绍使用 Jedis 访问 Redis 的一些基本方法。这里安装的 Redis 版本是 redis-5.0.4 稳定版。Redis 最广泛的应用场景就是使用它作为缓存,除此还有网站访问统计、数据过期处理(可以精确到毫秒)、应用排行榜、分布式集群架构中的 session 分离等。

使用 Jedis 需要添加 Maven 依赖:

<!-- redis -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.10.2</version>
</dependency>

1.Jedis的使用

1.xml配置方式

这里我们创建一个 Redis 操作的接口,分别创建两个实现类对应 Redis 的单机版和集群版。当使用单机版 Redis 时,配置单机版的实现类,当使用集群版的时候,配置集群版的实现类。

创建 JedisClient 接口:

public interface JedisClient {
    String set(String key, String value);
    String get(String key);
}

分别创建实现类:

public class JedisClientSingle implements JedisClient {
    @Autowired
    private JedisPool jedisPool;
    @Override
    public String set(String key, String value) {
        Jedis jedis = jedisPool.getResource();
        String result = jedis.set(key, value);
        jedis.close();
        return result;
    }
    //省略get实现
}
public class JedisClientCluster implements JedisClient {
    @Autowired
    private JedisCluster jedisCluster;
    @Override
    public String set(String key, String value) {
        return jedisCluster.set(key, value);
    }
    //省略get实现
}

然后增加配置 resources/spring-config-cache-redis.xml(单机版和集群版只能开一个):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- Redis连接池 -->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!-- 连接池最大连接数,使用负值表示没有限制,默认8 -->
        <property name="maxTotal" value="8"/>
        <!-- 连接池中的最大空闲连接,默认8 -->
        <property name="maxIdle" value="8"/>
        <!-- 连接池中的最小空闲连接,默认0 -->
        <property name="minIdle" value="0"/>
        <!-- 是否开启jmx监控,可用于监控,默认true,建议开启 -->
        <property name="jmxEnabled" value="true"/>
        <!-- 当连接池用尽后,调用者是否要等待,只有当为true时,下面的maxWaitMillis才会生效,默认true,建议使用默认值 -->
        <property name="blockWhenExhausted" value="true"/>
        <!-- 当连接池用尽后,调用者最大阻塞等待时间,默认-1L表示永不超时 -->
        <property name="maxWaitMillis" value="15000"/>
        <!-- 向连接池借用连接时是否做连接有效性检测(ping),无效连接会被移除,并尝试取出另一个,默认false,建议false -->
        <property name="testOnBorrow" value="false"/>
        <!-- 向连接池归还连接时是否做连接有效性检测(ping),无效连接会被移除,默认false,建议false -->
        <property name="testOnReturn" value="false"/>
        <!-- 在空闲时检查有效性,默认false -->
        <property name="testWhileIdle" value="true"/>
    </bean>

    <!-- 配置Redis客户端单机版 -->
    <bean id="jedisPool" class="redis.clients.jedis.JedisPool">
        <constructor-arg name="poolConfig" ref="jedisPoolConfig"/>
        <constructor-arg name="host" value="127.0.0.1"/>
        <constructor-arg name="port" value="6379"/>
        <constructor-arg name="timeout" value="3000"/>
        <constructor-arg name="password" value="123456"/>
    </bean>

    <!-- 配置Redis客户端集群版 -->
    <!--<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
        <constructor-arg>
            <set>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg index="0" name="host" value="127.0.0.1"/>
                    <constructor-arg index="1" name="port" value="6379"/>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg index="0" name="host" value="127.0.0.1"/>
                    <constructor-arg index="1" name="port" value="6380"/>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg index="0" name="host" value="127.0.0.1"/>
                    <constructor-arg index="1" name="port" value="6381"/>
                </bean>
            </set>
        </constructor-arg>
        <constructor-arg name="connectionTimeout" value="3000"/>
        <constructor-arg name="soTimeout" value="3000"/>
        <constructor-arg name="maxAttempts" value="3"/>
        <constructor-arg name="password" value="123456"/>
        <constructor-arg name="poolConfig" ref="jedisPoolConfig"/>
    </bean>-->

    <!-- 配置Redis客户端实现类 -->
    <bean id="redisClient" class="com.example.server.soa.dao.redis.impl.RedisClientSingle"/>
    <!--<bean id="redisClient" class="com.example.server.soa.dao.redis.impl.RedisClientCluster"/>-->
</beans>

然后在项目启动类中导入配置即可:

@SpringBootApplication
@ImportResource(
        "classpath:spring-config-cache-redis.xml"
)

使用的时候当作普通的类注入就可以了:

@Resource
private JedisClient jedisClient;

2.连接池配置优化

1、选择适合的 maxTotal,举个例子,命令平均执行时间为 0.1ms = 0.001s,如果业务需要 50000 QPS,则 maxTotal 理论值 = 0.001 * 50000 = 50 个。实际设置时要偏大一些。

实际上对于 maxTotal 需要考虑的事情比较多,大概有下面四点:

  • 业务希望 Redis 并发量;
  • 客户端执行命令时间;
  • Redis 资源,例如 应用个数 * maxTotal 是不能超过 Redis 的最大连接数的(config get maxclients);
  • 资源开销,例如 虽然希望控制空闲连接,但是不希望因为连接池的频繁释放创建连接造成不必要的开销。

建议 maxIdle = maxTotal,减少创建新连接的开销。
建议预热 minIdle,减少第一次启动后的新连接开销。

2、常见问题与解决思路:

报错:redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool …
Caused by: java.util.NoSuchElementException: Timeout waiting for idle object
原因:获取空闲连接的时候发生超时了。

报错:redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool …
Caused by: java.util.NoSuchElementException: Pool exhausted
原因:连接池里资源已经耗尽。

解决思路:

  1. 检查是否存在慢查询阻塞,连接池连接都被 hang 住了;
  2. 检查是否存在资源池参数不合理,例如 QPS 高、连接池小;
  3. 检查是否存在连接泄露(没有 close()),此类问题比较难定位,例如 client list、netstat 等,最重要的是代码;
  4. 检查是否存在 DNS 异常等。

2.基于Redis实现分布式应用限流

限流的目的是通过对并发访问/请求进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务。实际场景中常用的限流策略:

  • nginx接入层限流:按照一定的规则如帐号、IP、系统调用逻辑等在Nginx层面做限流。
  • 业务应用系统限流:通过业务代码控制流量这个流量可以被称为信号量,可以理解成是一种锁,它可以限制一项资源最多能同时被多少进程访问。
  • 数据库限流:红线区,力保数据库。

通过业务应用系统限流实现方案参考:https://my.oschina.net/giegie/blog/1525931

以上是关于Android NFC标签 开发深度解析 触碰的艺术的主要内容,如果未能解决你的问题,请参考以下文章

请问怎么确定OPPO手机是不是支持NFC功能

为啥这个 Haskell 代码使用fundeps 进行类型检查,但对类型族产生不可触碰的错误?

本周小贴士#120:返回值是不可触碰的

怎么开发 android nfc所支持的标签技术类型

android-ndk 对 NFC 编程有帮助吗?

Android NFC 标签读写Demo与历史漏洞概述