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也没有无参构造.... 谢谢~~
一年多之前 回复
tkk13
tkk13 我是从网上资料查到的:加载过程中会先检查类是否被已加载,检查顺序是自底向上,从Custom ClassLoader到BootStrap ClassLoader逐层检查,只要某个classloader已加载就视为已加载此类,保证此类只所有ClassLoader加载一次。而加载的顺序是自顶向下,也就是由上层来逐层尝试加载此类
一年多之前 回复
tkk13
tkk13 哦确实. 但是为什么会这样呢?我看网上的类加载器说法,按照我的理解是像刚才我说的,tomcat中将类型为RequestFacade的实例传入Filter接口中的doFilter方法中,此时类加载器中已经加载了RequestFacade,为什么到doFilter里面还会再加载一次?
一年多之前 回复
sycdzdd
sycdzdd 回复tkk13: 看你的反馈,一个是WebappClassLoader ,一个是StandardClassLoader,后者是前者的父类加载器,这应该就是问题所在
一年多之前 回复
tkk13
tkk13 这两个类加载器貌似是同一个? 我对类加载器不是特别了解.但看地址和名称都是一样的
一年多之前 回复
tkk13
tkk13 因为之前没法实现,我就直接手动进行增强类了,现在改回来用了点时间
一年多之前 回复
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
一年多之前 回复
tkk13
tkk13 回复程序员的微观世界: org.apache.catalina.loader.StandardClassLoader@72e3b895 -------------------------------------------------------- WebappClassLoader delegate: false repositories: /WEB-INF/classes/ ----------> Parent Classloader: org.apache.catalina.loader.StandardClassLoader@72e3b895
一年多之前 回复
sycdzdd
sycdzdd 回复tkk13: tomcat有一套自己的类加载器体系,共享lib、工程下自己的lib等
一年多之前 回复
sycdzdd
sycdzdd 回复tkk13: 我建议你打印下类的类加载器,这样比较清楚,传进来的是servletrequest,他向上转型成RequestFacade,肯定是向上找的同一个类加载器体系的
一年多之前 回复
tkk13
tkk13 tomcat加载了requestFacade后,传入到dofilter中,此时RequestFacade类应该已经存在于tomcat的类加载器中了,此时遇到我的代码里的该类型,应该会去类加载器中查找是否已经加载过,如果加载过则直接使用,不应该是这样吗?为什么会加载2次
一年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!
其他相关推荐
输出cglib以及jdk动态代理产生的class文件
输出cglib以及jdk动态代理产生的class文件
cglib 生成动态代理类的机制
转自  http://blog.csdn.net/luanlouis/article/details/24589193 cglib 生成动态代理类的机制----通过类继承:        JDK中提供的生成动态代理类的机制有个鲜明的特点是: 某个类必须有实现的接口,而生成的代理类也只能代理某个类接口定义的方法,比如:如果上面例子的ElectricCar实现了继承自两个接
深入浅出CGlib——打造无入侵的类代理
原文链接CGlib是什么? CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。 当然这些实际的功能是asm所提供的,asm又是什么?Java字节码操控框架,具体是什么大家可以上网查一查,毕竟我们这里所要讨论的是cglib, cglib就是封装了asm,简化了asm的操作,实现了在运行期动态生成新的class。 可能大家还感觉不到
CGLIB基于类创建动态代理要求类必须有无参构造器
一般在看错误堆栈信息时,我们应该从最后两个“Caused by”看起,如下就是。 这里一般都是根本原因的所在。 黄色的真心没看懂! 红色的意思大概是,无法创建“class com.springinaction.springidol.PoeticJuggler”这个CGLIB子类。 你会问,到底什么意思啊?别急,先让看看我做了什么操作才出现这个错误!   Caused by: org.s
JDK动态代理生成.class文件和cglib动态代理生成.class文件
一、JDK动态代理生成.class文件 接口: package cn.lut.dynamicproxy; public interface IHello { void sayHello(); } 实现类: package cn.lut.dynamicproxy; public class Hello implements IHello { public void sayHello(
查看CGLib生成的class文件方法
1.在程序最后一行加上一行System.in.read();阻塞住程序2.打开windows powershell 或者 cmd 执行 java -classpath "C:\Program Files\Java\jdk1.8.0_60\lib\sa-jdi.jar" sun.jvm.hotspot.HSDB3.在弹出的窗口中选择File-->Attach to HotSpot proces...
Spring AOP代理时 ClassCastException: $Proxy0 cannot be cast to (类型转换错误)
Spring AOP代理时 ClassCastException: $Proxy0 cannot be cast to  (类型转换错误) spring的文档中这么写的:Spring AOP部分使用JDK动态代理或者CGLIB来为目标对象创建代理,如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理。所有该目标类型实现的接口都将被代理。若该目标对象没有实现任何接口,则创建一个CGLIB
cglib动态代理以及出错解决
动态代理的代码使用的是这篇博客http://blog.csdn.net/yakoo5/article/details/9099133/public class Test { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); //通过生成子类的方式创建代理类
java-动态代理-jdk代理、cglib代理、生成字节码文件.
java-动态代理-jdk代理、cglib代理、生成字节码文件. 一、JDK动态代理和CGLIB字节码生成的区别?  * JDK动态代理只能对实现了接口的类生成代理,而不能针对类  * CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法    因为是继承,所以该类或方法最好不要声明成final  二、静态代理、动态代理区别? 静态代理:由程序员创建
Java中通过代理对类进行修改
JAVA中的静态代理、动态代理及JDK proxy和CGLIB、Javassist、ASM实践简介