JJwt耗时分析及优化

1 问题

在tomcat nio的框架下,每个请求都会有一个单独的tomcat 线程对请求进行处理。

通过Arthas观察发现,在请求中如果有jjwt的签名,有的请求耗时会非常高,高到3s ~ 4s.

查看源码,jjwt的签名方法compact(),有一处源码如下

// io/jsonwebtoken/impl/DefaultJwtBuilder.java

    @Override
    public String compact() {

        if (this.serializer == null) {
            // try to find one based on the services available
            // TODO: This util class will throw a UnavailableImplementationException here to retain behavior of previous version, remove in v1.0
            // use the previous commented out line instead
            this.serializer = LegacyServices.loadFirst(Serializer.class);
        }

    ....

    }

loadFirst方法最终会调用 ServiceLoader.load

private static <T> T loadFirst(Class<T> spi, ClassLoader classLoader) {
        ServiceLoader<T> serviceLoader = ServiceLoader.load(spi, classLoader);
        if (serviceLoader.iterator().hasNext()) {
            return serviceLoader.iterator().next();
        }
        return null;
    }

而SPI的这种实现方式,会遍历服务的JAR包,可能由于种种原因(作者未确认本文中jjwt耗时高的根因。),导致ServiceLoader hasNext高到3s多。

SPI相关参考 Java SPI 使用及原理分析 | 董宗磊的博客--靡不有初,鲜克有终

2 解决

其实jjwt compact方法给了注释

try to find one based on the services available

就是说我们提前给jjwt的builder指定解析器

jjwt依赖包中本身有提供jackson、gson的解析器,根据需求指定即可。

Date expiredTime = new Date(System.currentTimeMillis() + TTL);
        JwtBuilder builder = Jwts.builder()
                .setHeaderParam("typ", "JWT")
                .signWith(Keys.hmacShaKeyFor(SECRET.getBytes()))
                .setIssuer(ISS)
// 这一行指定了解析器。 (可以引入jjwt的jackson解析器包)
                .serializeToJsonWith(new JacksonSerializer<>());

        return builder
                .claim("yourClaim", "my personal claim")
                .setExpiration(expiredTime)
                .compact();

3 效果

本地测试

第一次使用jjwt的compact还是有300ms左右的耗时。

而后续使用的耗时为1ms以下

第一次的compact耗时跟进了一下源码。目前看是jac java安全相关的逻辑。

在第一次会加载相关的安全实例。

// jdk的依赖 javax/crypto/Mac.class


    public static final Mac getInstance(String var0) throws NoSuchAlgorithmException {
        List var1 = GetInstance.getServices("Mac", var0);
        Iterator var2 = var1.iterator();

        Service var3;
        do {
            if (!var2.hasNext()) {
                throw new NoSuchAlgorithmException("Algorithm " + var0 + " not available");
            }

            var3 = (Service)var2.next();
        } while(!JceSecurity.canUseProvider(var3.getProvider()));

        return new Mac(var3, var2, var0);
    }

PS:

跟社区提的ISSUE

JJwt Initialization is too Slow. Severer When it in a Concurrent System · Issue #692 · jwtk/jjwt · GitHub

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值