2 tkk13 tkk13 于 2017.01.09 13:07 提问

用CGLib对Tomcat的RequestFacade类构造动态代理类时发生的类型转换异常

我想在过滤器里返回代理后的servletrequest,发现其底层是tomcat的catlina包下的RequestFacade类,所以准备对它用cglib进行代理,增强其方法,此时发现对servletrequest强类转为RequestFacade时,报异常:
org.apache.catalina.connector.RequestFacade cannot cast to org.apache.catalina.connector.RequestFacade
RequestFacade这个类的包我是在lib中放入了tomcat/lib下的catlina.jar后才有的,这个包应该就是tomcat使用的包,请问问题出在哪里呢?~~

    public void doFilter(ServletRequest servletrequest,
            ServletResponse servletresponse, FilterChain filterchain)
            throws IOException, ServletException {
        //此处发生类型转换异常
        RequestFacade request = (RequestFacade)servletrequest;
        HttpServletResponse response = (HttpServletResponse)servletresponse;
        HttpServletRequest newrequest=new CGLibProxy(request).createProxy();
        String testString = newrequest.getRequestURL().toString();
        System.out.println(testString);
        filterchain.doFilter(newrequest, response);
    }

1个回答

sycdzdd
sycdzdd   2017.01.09 13:28
已采纳

传进来的requestfecade应该是由加载tomcat lib的类加载器加载的,而前面的requestfacade和当前filter类是同一个类加载器,而后面的类加载器
是filter类的父类加载器,所以无法从父类加载器转向子类,也有可能二者没有继承关系,没有试验,但是应该是这个原因导致的

tkk13
tkk13 回复程序员的微观世界: 看了一下类加载器,有点懂了,我把tomcat的核心包catalina.jar先放到classpath目录下,让java的加载器加载,就解决了这个问题了,因为作为java加载器的子类会先到上层加载器中找是否加载过..不过最后还是失败了,因为RequestFacade也没有无参构造.... 谢谢~~
11 个月之前 回复
tkk13
tkk13 我是从网上资料查到的:加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类
11 个月之前 回复
tkk13
tkk13 哦确实. 但是为什么会这样呢?我看网上的类加载器说法,按照我的理解是像刚才我说的,tomcat中将类型为RequestFacade的实例传入Filter接口中的doFilter方法中,此时类加载器中已经加载了RequestFacade,为什么到doFilter里面还会再加载一次?
11 个月之前 回复
sycdzdd
sycdzdd 回复tkk13: 看你的反馈,一个是WebappClassLoader ,一个是StandardClassLoader,后者是前者的父类加载器,这应该就是问题所在
11 个月之前 回复
tkk13
tkk13 这两个类加载器貌似是同一个? 我对类加载器不是特别了解.但看地址和名称都是一样的
11 个月之前 回复
tkk13
tkk13 因为之前没法实现,我就直接手动进行增强类了,现在改回来用了点时间
11 个月之前 回复
tkk13
tkk13 回复tkk13: tomcat传入的类的加载器是:org.apache.catalina.loader.StandardClassLoader@72e3b895 RequestFacade.class的类加载器是: WebappClassLoader delegate: false repositories: /WEB-INF/classes/ ----------> Parent Classloader: org.apache.catalina.loader.StandardClassLoader@72e3b895
11 个月之前 回复
tkk13
tkk13 回复程序员的微观世界: org.apache.catalina.loader.StandardClassLoader@72e3b895 -------------------------------------------------------- WebappClassLoader delegate: false repositories: /WEB-INF/classes/ ----------> Parent Classloader: org.apache.catalina.loader.StandardClassLoader@72e3b895
11 个月之前 回复
sycdzdd
sycdzdd 回复tkk13: tomcat有一套自己的类加载器体系,共享lib、工程下自己的lib等
11 个月之前 回复
sycdzdd
sycdzdd 回复tkk13: 我建议你打印下类的类加载器,这样比较清楚,传进来的是servletrequest,他向上转型成RequestFacade,肯定是向上找的同一个类加载器体系的
11 个月之前 回复
tkk13
tkk13 tomcat加载了requestFacade后,传入到dofilter中,此时RequestFacade类应该已经存在于tomcat的类加载器中了,此时遇到我的代码里的该类型,应该会去类加载器中查找是否已经加载过,如果加载过则直接使用,不应该是这样吗?为什么会加载2次
11 个月之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!