学习arthas(八)查找某个被加载的类

Arthas
placeholder image
admin 发布于:2023-09-30 14:41:52
阅读:loading

1.基本介绍

有些时候查找某个被加载的类也是有必要的,当然抛出ClassNotFound异常的除外,特别是针对于需要改写一些第三方框架组件的源代码时,也许是因为源码中的实现不够理想,要么是需要做一些个性化的事情,通常我们的做法并不是去改写这些三方库的源代码jar,而是拷贝一份源代码放置于项目中的同包名同类名,再调整启动脚本优先加载项目内的classes或jar,而后再加载这些第三方的jar,使得预先加载的是项目中的代码(项目中修改过的代码)。所以,基本上有这几种场景是这么干过:

(1)在使用Google的zxing生成二维码组件时,由于它默认生成的二维码带有一些宽度的白色边框(差不多10像素),如果需要取消白边,通常的做法就是改动源代码(本站有对于此问题的解决);

(2)在使用第三方登录时(如:QQ、微博等)它们提供的SDK示例程序的参数都使用配置文件存储的,本站在实现时将这些配置文件存储于数据库中,所以也通过改项目类加载的形式解决;

(3)本站在使用Spring Session做的session管理,但是又不明确它的过滤器拦截的URL范围是什么样子的,所以也可以通过改写它的过滤器的方式增加一些日志输出,用于分析它的URL拦截范围;

(4)工作中也有在升级JPA后使用它的命名方法报错的场景,领导在对于源码分析调试后发现高版本的JPA对于命名方法的属性解析实现做了更改,以至于前期所写的巨多老代码失效了,也通过这种方式改写的源代码进行覆盖解决;

所以,本次实践的目的是使用arthas来分析项目中的两个同包同名的类具体来自于哪个jar包当中的实现,以Spring Session中的过滤器代码覆盖为例,我需要覆盖spring session中的过滤器,因为它默认将拦截全部的路径,导致一个页面中引入的JS、CSS、IMAGE、FONT等各个资源都被拦截,导致页面响应超慢,所以我需要覆盖实现它,详细如下文所示。

2.参考代码

package org.springframework.boot.autoconfigure.session;

import ...;

/**
 * Configuration for customizing the registration of the {@link SessionRepositoryFilter}.
 *
 * @author Andy Wilkinson
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(SessionRepositoryFilter.class)
@EnableConfigurationProperties(SessionProperties.class)
@Slf4j
public class SessionRepositoryFilterConfiguration {

    @Bean
    FilterRegistrationBean<SessionRepositoryFilter<?>> sessionRepositoryFilterRegistration(
            SessionProperties sessionProperties, SessionRepositoryFilter<?> filter) {
        log.warn("注意:已使用SessionRepositoryFilterConfiguration重载实现");
        //定义session 拦截路径范围
        FilterRegistrationBean<SessionRepositoryFilter<?>> registration = new FilterRegistrationBean<>(filter);
        registration.addUrlPatterns("*.html" , "*.zip" , "*.exe" , "/system/login" , "/" , "/index.html" ,
                "/third-login/loginCallback" , "/third-login/baiduCallback" ,  "/tencent-login/tencentCallback" ,
                "/swagger-resources" , "/swagger-resources/**");
        registration.addInitParameter("excludeUrls", "/statics/**");
        registration.setDispatcherTypes(getDispatcherTypes(sessionProperties));
        registration.setOrder(sessionProperties.getServlet().getFilterOrder());
        return registration;
    }

    private EnumSet<DispatcherType> getDispatcherTypes(SessionProperties sessionProperties) {
        SessionProperties.Servlet servletProperties = sessionProperties.getServlet();
        if (servletProperties.getFilterDispatcherTypes() == null) {
            return null;
        }
        return servletProperties.getFilterDispatcherTypes().stream().map((type) -> DispatcherType.valueOf(type.name()))
                .collect(Collectors.collectingAndThen(Collectors.toSet(), EnumSet::copyOf));
    }

}

3.查找类验证

image.png

(启动脚本)

启动脚本共引入了三个文件夹中的jar,分别是如下场景,按优先指定的顺序,可以起到优先加载的目的,所以若“org.springframework.boot.autoconfigure.session.SessionRepositoryFilterConfiguration”类在lib-local范围被定义,同时也在lib-jar中被定义,那么最终生效的则是lib-local中的class,除了可以使用Log输出日志来证明外,现在使用arthas来展示结果,所以参考如下图所示:

image.png

(验证结果一)

image.png

(验证结果二)

4.反编译类验证

使用arthas里的jad也可以查看已加载的类的所在位置和反编译后的源码,如下图所示:

image.png


 点赞


 发表评论

当前回复:作者

 评论列表


留言区