jdk与cglib动态代理

静态代理与动态代理
静态代理:代理类在代码运行之前已经生成
动态代理:代理类对象是代码动态生成的(反射)

java中实现动态代理主要有两种方式,jdk动态代理与cglib动态代理。
jdk动态代理依靠实现类的接口实现,因此被代理的类必须要实现某个接口。
cglib依靠继承被代理的类的子类实现,因此被代理的类必须不能是final类型的类,且被代理的方法也不能是final类型方法,如果被代理的方法为final方法,则代理方法失效,直接运行原始方法。
spring中动态代理是依靠两者同时实现的,一般情况下spring会优先使用jdk动态代理,如果发现被代理的类不能使用jdk动态代理则使用cglib动态代理,当然spring配置时也可以强制使用cglib动态代理,配置方法:

<aop:config proxy-target-class="true">

使用jdk动态代理

首先定义一个被代理类

public interface IHello 
{
    public void say();
}

定义一个被代理类的实现

public class Hello implements IHello
{
    private String name;

    public Hello(String name)
    {
        super();
        this.name = name;
    }

    public void say()
    {
        System.out.println("hello:" + name);
    }
}

jdk动态代理类

public class MyInvocationHandler implements InvocationHandler
{

    private Object target;

    public MyInvocationHandler(Object target)
    {
        super();
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable
    {
        System.out.println("------------------before------------------");
        // 执行目标对象的方法
        Object result = method.invoke(target, args);
        // 在目标对象的方法执行之后简单的打印一下
        System.out.println("-------------------after------------------");
        return result;
    }
}

测试方法:

    @org.junit.Test
    public void test()
    {
        MyInvocationHandler invocationHandler = new MyInvocationHandler(new Hello("csdn"));
        IHello hello = (IHello)Proxy.newProxyInstance(AppTest.class.getClassLoader(),
            new Class[] {IHello.class},
            invocationHandler);
        hello.say();
    }

以上就是jdk动态代理的一个简单的实例,要实现jdk动态代理需要被代理类实现一个接口,动态代理类其实是实现了这个接口的一个代理类,会调用代理类和被代理类的方法

cglib实现动态代理:
由于cglib不需要依靠接口实现,而是直接继承被代理类,因此不需要定义接口
被代理类:

public class Hello
{
    private String name;

    public Hello(String name)
    {
        super();
        this.name = name;
    }

    public void say()
    {
        System.out.println("hello:" + name);
    }
}

动态代理类:

public class CglibProxy implements MethodInterceptor
{

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
        throws Throwable
    {
        // 添加切面逻辑(advise),此处是在目标类代码执行之前,即为MethodBeforeAdviceInterceptor。
        System.out.println("------------------before------------------");
        // 执行目标类add方法
        Object object = proxy.invokeSuper(obj, args);
        // 添加切面逻辑(advise),此处是在目标类代码执行之后,即为MethodAfterAdviceInterceptor。
        System.out.println("------------------after------------------");
        return object;
    }
}

测试方法:

 @org.junit.Test
    public void testCglib()
    {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Hello.class);
        // 回调方法的参数为代理类对象CglibProxy,最后增强目标类调用的是代理类对象CglibProxy中的intercept方法
        enhancer.setCallback(new CglibProxy());
        // 此刻,hello不是单纯的目标类,而是增强过的目标类
        Hello hello = (Hello)enhancer.create(new Class[] {String.class}, new Object[] {"csdn"});
        hello.say();
    }

输出:

------------------before------------------
hello:csdn
------------------after------------------

cglib实现动态代理时,可以使用CallbackFilter来实现过滤,使得不同的方法使用不同的回调
修改Hello.java

public class Hello
{
    private String name;

    public Hello(String name)
    {
        super();
        this.name = name;
    }

    public void say()
    {
        System.out.println("hello:" + name);
    }

    public void sayNotProxy()
    {
        System.out.println("not proxy hello:" + name);
    }
}

实现一个CallbackFilter类

public class CglibCallbackFilter implements CallbackFilter
{

    @Override
    public int accept(Method method)
    {
        if ("say".equals(method.getName()))
        {
            return 1;
        }
        return 0;
    }

}

测试方法:

@org.junit.Test
    public void testCglib()
    {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Hello.class);
        // 设置回调filer,accept方法返回的值即为代理方法使用的回调类型
        enhancer.setCallbacks(new Callback[] {NoOp.INSTANCE, new CglibProxy()});
        enhancer.setCallbackFilter(new CglibCallbackFilter());
        // 此刻,hello不是单纯的目标类,而是增强过的目标类
        Hello hello = (Hello)enhancer.create(new Class[] {String.class}, new Object[] {"csdn"});
        hello.say();
        hello.sayNotProxy();
    }

输出结果:

------------------before------------------
hello:csdn
------------------after------------------
not proxy hello:csdn

可见方法sayNotProxy并没有使用代理方法,回调类型的定义如下:
net.sf.cglib.proxy.FixedValue:在强制一个特定方法返回固定值,在特定场景下非常有用且性能高。
net.sf.cglib.proxy.NoOp:它直接透传到父类的方法实现。
net.sf.cglib.proxy.LazyLoader:在被代理对象需要懒加载场景下非常有用,如果被代理对象加载完成,那么在以后的代理调用时会重复使用。
net.sf.cglib.proxy.Dispatcher:与net.sf.cglib.proxy.LazyLoader差不多,但每次调用代理方法时都会调用loadObject方法来加载被代理对象。
net.sf.cglib.proxy.ProxyRefDispatcher:与Dispatcher相同,但它的loadObject方法支持传入代理对象。

关于cglib动态代理还需要注意一件事,网上很多地方说cglib动态代理时必须要有无参构造,其实这个说法是错误的,只要在创建代理时,指明参数类型与参数值,其实是可以动态生成没有无参构造类的代理对象的。

关于两者的性能比较,测试代码如下:

public class AppTest
{
    private int preRunCount = 100000;

    private int runCount = 1000;

    @org.junit.Test
    public void test()
        throws InterruptedException
    {
        System.gc();
        Thread.sleep(2000);
        MyInvocationHandler invocationHandler = new MyInvocationHandler(new Hello());
        IHello hello = (IHello)Proxy.newProxyInstance(AppTest.class.getClassLoader(),
            new Class[] {IHello.class},
            invocationHandler);
        for (int i = 0; i < preRunCount; i++)
        {
            hello.say();
        }

        long start = System.currentTimeMillis();
        for (int i = 0; i < runCount; i++)
        {
            hello.say();
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }

    @org.junit.Test
    public void testCglib()
        throws InterruptedException
    {
        System.gc();
        Thread.sleep(2000);

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Hello.class);
        enhancer.setCallback(new CglibProxy());
        Hello hello = (Hello)enhancer.create();
        for (int i = 0; i < preRunCount; i++)
        {
            hello.say();
        }



        long start = System.currentTimeMillis();
        for (int i = 0; i < runCount; i++)
        {
            hello.say();
        }
        long end = System.currentTimeMillis();
        System.out.println(end - start);
    }
}

两者测试比较时jdk动态代理创建对象时的确比cglib快很多,但两者执行时的运行效率并没有像网上说的cglib运行效率是jdk动态代理的十倍,实际运行时两者的运行效率差不太多,有时jdk的运行效率反而比cglib代理时的要快

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值