<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    VIRGIN FOREST OF JAVA
    不要埋頭苦干,要學習,學習,再學習。。。。。
    powered by R.Zeus

    The Pitfalls of Dynamic Proxy Serialization

    Created by Caleb Powell. Last edited by Caleb Powell, 195 days ago.

    Recently, we ran into problems de-serializing proxy objects. The first pitfall involved a bug in Weblogic that prevented us from de-serializing a java.lang.reflect.Proxy instance. The second pitfall occurred as a result of using a Cglib proxy. In our efforts to deal with these pitfalls we deepened our understanding of how these libraries create dynamic proxies.

    Pitfall #1: Classloader Problems

    We wanted to use the java.lang.reflect.Proxy class to make instances of one (very simple) class assignable to different types of interfaces. Everything was going just swimingly and we were close to checking in our code. When it came time to run our integration tests, Weblogic began throwing a ClassNotFoundException whenever it attempted to de-serialize a proxy instance in a MessageDrivenBean. Once we confirmed that the interfaces were indeed on the Classpath, we fired up the debugger and dug a little deeper (but not until we consumed a a copious amount of Coca-Cola and Marlboros... thanks for the tip Mike). We discovered that - in the process of de-serializing our proxy object - the java.io.ObjectInputStream was trying to load our interfaces with the wrong classloader. It was using the parent of the Weblogic application classloader which had no knowledge of the classpath in our EAR file. We were were pretty certain that the reason was due to a bug in the way Weblogic was managing classloaders in it's JMS implementation (of course, Weblogic is not open source so we can't be 100% certain of this).

    We couldn't de-serialize the object ourselves inside the message bean and we couldn't modify the way Weblogic managed classloaders, so we tried using the Cglib library instead. The Cglib proxy worked? The reason is because the ObjectInputStream de-serializes Cglib instances differently than it does a java.lang.reflect.Proxy instance. Why? Because of a key difference between the two types of proxy objects;

    • When you create an instance using the JDK Proxy, it generates a subclass of the java.lang.reflect.Proxy class for you (the subclass is assignable to any interfaces you provide). Furthermore, the class generated by the java.lang.reflect.Proxy will have a different class descriptor (in fact, a Proxy class descriptor).
    • On the other hand, the Cglib library generates a subclass of an arbitrary class that you provide (as with the JDK proxy, the Cglib generated subclass will also be assignable to any interfaces you choose to provide). The class generated by the Cglib library will have a regular class descriptor.

    Whenever the ObjectInputStream de-serializes an object, it peeks at the Class descriptor. If it has a Proxy class descriptor, it invokes the ObjectInputStream.resolveProxyClass() method which creates a new version of the proxy subclass in the JVM (if it didn't already exist) based on the declared interfaces. Because the Cglib class has a normal class descriptor, the ObjectInputStream.resolveClass() method is invoked instead. For reasons we're not sure of, the classloader that is retrieved in the ObjectInputStream.resolveClass() method is the correct one and can resolve our interfaces/classes.

    Pitfall #2: Generated Subclasses

    Now our Cglib proxy was being de-serialized correctly when sent to a JMS MessageDrivenBean. But we we were also sending these proxies to a rich client, and the Cglib proxies were not being de-serialized there. We were stunned, but only temporarily. This result was to be expected. The Cglib generated objects were instances of a subclass generated dynamically on a different JVM. Our rich client JVM didn't recognize the class and was quite justified in throwing a ClassNotFoundException.

    It turns out there is a pretty simple solution to this problem. Basically, you need to implement the writeReplace() and readResolve() methods on the object that your proxy delegates methods to. The delegate uses these methods to de-proxy and re-proxy itself depending on whether it is being serialized or de-serialized. In our case, our delegate object is the super-class of our Proxy instance, so we implemented the writeReplace() and readResolve() methods on it. Here is an example using a class called DataHandler;

    public static class DataHandler implements Serializable {
    private static final long serialVersionUID = 1L;
    private final String someData;

    public DataHandler(String someData){
    this.someData = someData;
    }
    public String getSomeData() {
    return someData;
    }

    public boolean equals(Object obj) {
    return obj instanceof DataHandler ?
    ((DataHandler)obj).getSomeData().equals(this.someData)
    : false;
    }

    public Object writeReplace() throws ObjectStreamException{
    return new DataHandler(this.someData);
    }
    public Object readResolve() throws ObjectStreamException{
    return ProxyFactory.createCglibProxy(DataHandler.class, new Class[]{IFoo.class}, new Object[] {this.someData});
    }
    }

    public interface IFoo extends java.io.Serializable{
    }
    We create a proxy with the Cglib library like so;
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(DataHandler.class);
    enhancer.setInterfaces(new Class[]{IFoo.class});
    enhancer.setCallback(new NoOpCallback());//a NoOp callback. All methods will be invoked on the superclass

    //generates a subclass of DataHandler that is assignable to the IFoo interface.
    IFoo foo = (IFoo) enhancer.create(new Class[]{String.class}, new Object[] {"someData"});
    When the foo instance is serialized, the super-class (DataHandler) method writeReplace() is invoked. The writeReplace method returns a new instance of the DataHandler class, thereby discarding the Proxy wrapper subclass. It's this new instance of DataHandler that gets serialized, not the original subclass. When the DataHandler instance is eventually de-serialized, the readResolve() method is invoked on it. The readResolve() will generate and return a new proxy subclass equivalent to the original. We learned this little trick by studying the code in the Hibernate project which uses Cglib for proxies and is open-source.



    posted on 2008-08-25 13:29 R.Zeus 閱讀(297) 評論(0)  編輯  收藏 所屬分類: Reflection 、CGLIB
    主站蜘蛛池模板: 亚洲无人区一区二区三区| 国产大片91精品免费观看男同 | 亚洲AV永久无码精品一福利| 18女人毛片水真多免费| 亚洲AV无码乱码在线观看富二代 | 一级黄色片免费观看| 免费人成视频在线观看不卡| 欧洲亚洲国产精华液| 国产三级电影免费观看| 四虎国产精品成人免费久久| 久久久久亚洲av成人无码电影 | 国产精品无码免费专区午夜| 亚洲精品国产字幕久久不卡| 中文字幕在线视频免费| 亚洲av无码潮喷在线观看| 2019中文字幕在线电影免费| 亚洲xxxxxx| 免费二级毛片免费完整视频| 国产精品成人免费观看| 久久综合九九亚洲一区| 五月亭亭免费高清在线| 亚洲人成色777777精品| 亚洲熟女乱综合一区二区| 精品视频在线免费观看| 亚洲AV无码专区在线亚| 四虎影视免费永久在线观看| 国产久爱免费精品视频| 久久精品国产亚洲77777| 在线观看免费成人| a级毛片免费网站| 亚洲成人免费网站| 国产一级理论免费版| 国产一级淫片a免费播放口| 亚洲乱码无限2021芒果| 亚洲色偷拍区另类无码专区| 精品无码无人网站免费视频| 久久亚洲AV成人无码国产电影| 亚洲欧洲国产精品香蕉网| 中文字幕人成无码免费视频| 精品国产福利尤物免费| 亚洲xxxxxx|