zoukankan      html  css  js  c++  java
  • JDK动态代理与CGLib动态代理

    JDK动态代理:

    a、先定义一个接口,这个接口中的方法是“目标方法”

    package com.brickworkers;
    
    public interface Sky {
    
        public void rain();
    
    }

    b、接着写一个这个接口的具体实现:

    package com.brickworkers;
    
    public class SkyImpl implements Sky{
    
        @Override
        public void rain() {
            System.out.println("it`s raining");
        }
    
    
    }

    c、如果要完成动态代理,首先需要定义一个InvocationHandler接口的子类:

    package com.brickworkers;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    public class MyInvocationHandler implements InvocationHandler {
    
        //目标对象
        private Object obj = null;
    
    
        //获取目标对象的代理对象
        public Object getProxy(Object obj){
            this.obj = obj;
            return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
        }
    
        //控制执行目标对象的方法
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("目标对象方法执行之前");
            Object result = method.invoke(obj, args);
            System.out.println("目标对象方法执行之后");
            return result;
        }
    
    }

    d:JDK动态代理测试类:

    package com.brickworkers;
    
    public class ProxyTest {
    
        public static void main(String[] args) {
            //实例化InvocationHandler
            MyInvocationHandler myInvocationHandler = new MyInvocationHandler();
            //生产代理对象
            Sky sky = (Sky) myInvocationHandler.getProxy(new SkyImpl());
            sky.rain();
        }
    
    }
    
    //执行结果:  目标对象方法执行之前
    //            it`s raining
    //          目标对象方法执行之后

    为什么JDK动态代理只能局限于接口呢?查阅了一些技术文档和JDK动态代理的源码,发现在反编译产生的proxyTest.class中,类的定义如下:

    import dynamic.proxy.UserService;  
    import java.lang.reflect.*;  
    
    public final class $ProxyTest extends Proxy  
        implements Sky
    { 
        ......
    }

    从反编译的源码可以看出,proxyTest继承了Proxy,然而在Java中只支持单继承,但是可以实现多个接口,所以JDK动态代理只能局限于接口。

    那么JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,要实现动态代理要怎么办呢?这个时候就需要CGLib动态代理了。

    CGLib动态代理:

    CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有分类方法的调用,顺势织入和横切逻辑。-http://blog.csdn.net/yakoo5/article/details/9099133/

    点击下载编写CGlib动态代理测试所需jar包

    a、定义一个目标对象:

    package com.brickworkers;
    
    public class Color {
    
        public void showColor(){
            System.out.println("red");
        }
    
    }

    b、如果要完成动态代理,首先需要定义一个MethodInterceptor接口的子类:

    package com.brickworkers;
    
    import java.lang.reflect.Method;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    public class MyCglib implements MethodInterceptor {
    
        //目标对象
        private Object obj = null;
    
        public Object getProxy(Object obj){
            this.obj = obj;
            Enhancer enhancer = new Enhancer();  
            enhancer.setSuperclass(obj.getClass());
            // 回调方法  
            enhancer.setCallback(this);  
            // 创建代理对象  
            return enhancer.create();
    
        }
    
        @Override
        public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("目标对象方法执行之前");
            Object result = methodProxy.invoke(obj, args);
            System.out.println("目标方法执行之后");
            return result;
        }
    
    }

    c、CGLib动态代理测试类:

    package com.brickworkers;
    
    public class CGLibTest {
    
        public static void main(String[] args) {
            MyCglib myCglib = new MyCglib();
            Color color = (Color) myCglib.getProxy(new Color());
            color.showColor();
        }
    }
    //执行结果:目标对象方法执行之前
    //              red
    //          目标方法执行之后

    因为CGLib动态代理是创建一个子类来实现的,那么对于继承的定义,final类是无法进行代理的。

  • 相关阅读:
    mysql 设置密码
    linux 下如何抓取HTTP流量包(httpry)
    m2a-vm超频的方法
    生产服务器环境最小化安装后 Centos 6.5优化配置备忘
    CentOS关闭休眠和屏保模式
    微信公众平台开发教程第2篇-----微信开发者接入
    微信公众平台开发教程第1篇-新手解惑
    android 文件读取(assets、raw)
    员工培训的七大误区和三个内核价值
    从业务专家进阶到管理者
  • 原文地址:https://www.cnblogs.com/wyb628/p/8511174.html
Copyright © 2011-2022 走看看