[zt] cglib2 proxy tutorial

http://alexwinston.com/blog/2004/03/23/1080068110000.html 
for those that are familiar with aop will have most certainly heard of cglib. for those that have not, cglib provides the ability instrument bytecode programmatically. it uses asm for the heavy lifting, and provides a simple interface to extend any non-final class as well as implement interfaces at runtime. i myself am rather new to cglib and cglib2 and have found examples rather lacking so i have decided to put together an example that concisely shows all of the power of cglib2's proxying prowess. if anyone finds this useful i might put together additional tutorials as well. please feel free to submit feedback.

unfortunately the cglib website does not do a very good job of selling the power of it's library. the documentation is scarce, the examples are thin, and i was is left scratching my head as to exactly how to utilize this powerful tool. fortunately the test cases are rather complete so after digging around i was able to piece together almost all of the proxying power of cglib. the example below will begin with several simple classes that we can either extend of implement with cglib -- below i will outline how to intercept methods, add mixins, and make proxies "aware" with the cglib Enhancer.

first we start with several simple interfaces Foo, Bar, and FooBar.

 

public interface Foo {
    public void foo();
}

public interface Bar {
    public void bar();
}

public interface FooBar extends Foo, Bar {
}


next we provide very simple implementations of the Foo and Bar interfaces.


import java.io.Serializable;

public class FooImpl implements Foo, Serializable {
    public void foo() {
        System.out.println("foo");
    }
}

import java.io.Serializable;

public class BarImpl implements Bar, Serializable {
    public void bar() {
        System.out.println("bar");
    }
}


next we provide a simple interceptor implementation to log method calls.

public class LoggingInterceptor implements MethodInterceptor {
    public Object intercept(Object obj, Method method,
            Object[] args, MethodProxy proxy) throws Throwable {
        try {
            System.out.println("before " + method);
            return proxy.invokeSuper(obj, args);
        } finally {
            System.out.println("after " + method);
        }
    }
}


once this is done we can instruct cglib to enhance our classes accordingly. the first example shows how we can extend the superclass FooImpl by implementing the Bar interface and dispatch to the implementation and intercepting method calls. you will also notice that we are instructing cglib to implement the FooBar interface -- the purpose is to consolidate our interfaces into one "aware" interface so we do not have to cast to each interface cglib implemented for us.


public void testExtendingSuperclass() throws Exception {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(FooImpl.class);
    enhancer.setInterfaces(new Class[] { Bar.class, FooBar.class });
    enhancer.setCallbackTypes(new Class[] {
        Dispatcher.class, MethodInterceptor.class });
    enhancer.setCallbackFilter(new CallbackFilter() {
        public int accept(Method method) {
            if (Bar.class.isAssignableFrom(method.getDeclaringClass()))
                return 0;
            else
                return 1;
        }
    });

    Class clazz = enhancer.createClass();

    enhancer.registerCallbacks(clazz, new Callback[] {
        new Dispatcher() {
            public Object loadObject() {
                return Enhancer.create(BarImpl.class,
                    new LoggingInterceptor());
            }
        },
        new LoggingInterceptor()
    });


    FooBar foobar = (FooBar) clazz.newInstance();
    foobar.foo();
    foobar.bar();
}


the next example shows how we can have cglib create a new Class for us without extending a superclass. in this example we are dispatching to all the implementation that cglib has implemented for us.


public void testNoSuperclass() throws Exception {
    Enhancer enhancer = new Enhancer();
    enhancer.setInterfaces(new Class[] {
        Foo.class, Bar.class, FooBar.class });
    enhancer.setCallbackTypes(new Class[] {
        Dispatcher.class, Dispatcher.class });
    enhancer.setCallbackFilter(new CallbackFilter() {
        public int accept(Method method) {
            return Foo.class.isAssignableFrom(
                method.getDeclaringClass()) ? 0 : 1;
        }
    });
    /*
    enhancer.setStrategy(new DefaultGeneratorStrategy() {
        protected byte[] transform(byte[] b) {
            try {
                FileOutputStream fos =
                    new FileOutputStream("build/Cglib2Generated.class");
                fos.write(b);
            } catch (Exception e) {
                e.printStackTrace();
            }

            return b;
        }
    });
    */

    Class clazz = enhancer.createClass();

    enhancer.registerCallbacks(clazz, new Callback[] {
        new Dispatcher() {
            public Object loadObject() {
                return Enhancer.create(FooImpl.class,
                    new LoggingInterceptor());
            }
        },
        new Dispatcher() {
            public Object loadObject() {
                return Enhancer.create(BarImpl.class,
                    new LoggingInterceptor());
            }
        }
    });


    FooBar foobar = (FooBar) clazz.newInstance();
    foobar.foo();
    foobar.bar();
}


with these simple examples we are on our way to fully utilizing the power of cglib proxies. you may also notice that i have commented out setting the strategy in the second example. this is a very powerful undocumented feature that allows us to directly access the byte[] of our proxy. i hope this provides some valuable insight into how you can use cglib to it's fullest.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值