• JDK动态代理和CGLib动态代理简单演示


    JDK1.3之后,Java提供了动态代理的技术,允许开发者在运行期间创建接口的代理实例。

    一、首先我们进行JDK动态代理的演示。

    现在我们有一个简单的业务接口Saying,如下:

    package testAOP;
    public interface Saying {
    public void sayHello(String name);    
    public void talking(String name);
    }

    一个简单的实现类SayingImpl,如下:

    package testAOP;
    public class SayingImpl implements Saying {
        @Override
        public void sayHello(String name) {
            // TODO Auto-generated method stub
            System.out.println(name + ":大家好啊!");
        }
        @Override
        public void talking(String name) {
            // TODO Auto-generated method stub
            System.out.println(name + ":我的意思是,我们要努力建设和谐社会!");
        }
    }

    我们要实现的是,在sayHello和talking之前和之后分别动态植入处理。

    JDK动态代理主要用到java.lang.reflect包中的两个类:Proxy和InvocationHandler.

    InvocationHandler是一个接口,通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态的将横切逻辑和业务逻辑编织在一起。

    Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。

    如下,我们创建一个InvocationHandler实例:

    package testAOP;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class MyInvocationHandler implements InvocationHandler {
    
        private Object target;
        MyInvocationHandler(Object target){
            this.target = target;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            //目标方法前执行
            System.out.println("——————————————————————————");
            System.out.println("下一位请登台发言!");
            //目标方法调用
            Object obj = method.invoke(target, args);
            //目标方法后执行
            System.out.println("大家掌声鼓励!");
            return obj;
        }
    }

    下面是测试:

    package testAOP;
    
    import java.lang.reflect.Proxy;
    
    public class JDKProxyTest {
        
        public static void main(String[] args) {
            // 希望被代理的目标业务类
            Saying target = new SayingImpl();
            // 将目标类和横切类编织在一起
            MyInvocationHandler handler = new MyInvocationHandler(target);
            // 创建代理实例
            Saying proxy = (Saying) Proxy.newProxyInstance(
                    target.getClass().getClassLoader(),//目标类的类加载器
                    target.getClass().getInterfaces(),//目标类的接口
                    handler);//横切类
            proxy.sayHello("小明");
            proxy.talking("小丽");
        }
    }

    运行情况如下:

    ——————————————————————————
    下一位请登台发言!
    小明:大家好啊!
    大家掌声鼓励!
    ——————————————————————————
    下一位请登台发言!
    小丽:我的意思是,我们要努力建设和谐社会!
    大家掌声鼓励!

    使用JDK动态代理有一个很大的限制,就是它要求目标类必须实现了对应方法的接口,它只能为接口创建代理实例。我们在上文测试类中的Proxy的newProxyInstance方法中可以看到,该方法第二个参数便是目标类的接口。如果该类没有实现接口,这就要靠cglib动态代理了。

    CGLib采用非常底层的字节码技术,可以为一个类创建一个子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势植入横切逻辑。

    二、接下来我们进行cglib动态代理的演示。

    首先我们需要导包,我用的包是cglib-nodep-2.1_3.jar。

    我们首先创建一个代理创建器CglibProxy:

    package testAOP.cglib;
    
    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 CglibProxy implements MethodInterceptor{
    
        Enhancer enhancer = new Enhancer();
        public Object getProxy(Class clazz) {
            //设置需要创建的子类
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
            //通过字节码技术动态创建子类实例
            return enhancer.create();
        }
        @Override
        public Object intercept(Object obj, Method method, Object[] args,
                MethodProxy proxy) throws Throwable {
            // TODO Auto-generated method stub
            System.out.println("——————————————————————————");
            System.out.println("下一位请登台发言!");
            //目标方法调用
            Object result = proxy.invokeSuper(obj, args);
            //目标方法后执行
            System.out.println("大家掌声鼓励!");
            return result;
        }    
    }

    然后进行测试:

    package testAOP.cglib;
    
    import testAOP.Saying;
    import testAOP.SayingImpl;
    
    public class CglibProxyTest {
    
        public static void main(String[] args) {
            CglibProxy proxy = new CglibProxy();
            //通过动态生成子类的方式创建代理类
            Saying target = (Saying) proxy.getProxy(SayingImpl.class);
            target.sayHello("小明");
            target.talking("小丽");
        }
    }

    结果与JDK动态代理没有任何区别。

    CGLib动态代理能代理类和接口,但是不能代理final类,也是有一定局限性。

    JDK动态代理和CGLib动态代理都是运行时增强,通过将横切代码植入代理类的方式增强。与此不同的是AspectJ,它能够在通过特殊的编译器在编译时期将横切代码植入增强,这样的增强处理在运行时候更有优势,因为JDK动态代理和CGLib动态代理每次运行都需要增强。

    /**
    *   ————————如果觉得本博文还行,别忘了推荐一下哦,谢谢!
    *   作者:钱书康
    *   欢迎转载,请保留此段声明。
    *   出处:http://www.cnblogs.com/zrtqsk/
    */
  • 相关阅读:
    对于“机器视觉(computer version)”的反思
    图像视觉的调试
    对自主标定的实现
    使用dll,将image库开放出去
    使用liner、feather、multiband对已经拼接的数据进行融合(下)
    使用liner、feather、multiband对已经拼接的数据进行融合
    模版多匹配
    Metasploit AFP爆破模块afp_login
    SQLite中SELECT基本形式
    Nmap 7.70新增功能——扫描主机所有IP
  • 原文地址:https://www.cnblogs.com/zrtqsk/p/3600588.html
Copyright © 2020-2023  润新知