zoukankan      html  css  js  c++  java
  • 013 Enhancer创建动态代理

      在上一章使用了Enhancer,没有仔细说明代理的问题,在这一章进行详细的说明。

      原本想使用cf包的,后来发现使用framework包下的包也没有问题,程序中就一直使用framework中的类。

    一:概述

    1.说明

      CGLIB是一个强大、高性能的字节码生成库,它用于在运行时扩展Java类和实现接口;

      本质上它是通过动态的生成一个子类去覆盖所要代理的类(非final修饰的类和方法)。

      Enhancer是一个非常重要的类,它允许为非接口类型创建一个JAVA代理,Enhancer动态的创建给定类的子类并且拦截代理类的所有的方法,和JDK动态代理不一样的是不管是接口还是类它都能正常工作。

    2.回调接口

      net.sf.cglib.proxy.Callback接口:在cglib包中是一个很关键的接口,所有被net.sf.cglib.proxy.Enhancer类调用的回调(callback)接口都要继承这个接口
      net.sf.cglib.proxy.MethodInterceptor接口:   是通用的回调(callback)类型,他经常被AOP用来实现拦截(intercept)方法的调用;

     3.关于MethodInterceptor接口的源代码

      是Callback的子接口,所以,实现这个接口的类可以用于回调。

    package org.aopalliance.intercept;
    
    @FunctionalInterface
    public interface MethodInterceptor extends Interceptor {
        Object invoke(MethodInvocation var1) throws Throwable;
    }

    二:示例

    1.结构

      

    2.对象

    package com.jun.web.enhancer;
    
    public class HelloWorld {
        public String say(boolean say) throws Exception {
            System.out.println("Hello Student");
            if(!say) {
                throw new Exception("回答错误!");
            }
            return "回答正确!";
        }
    }

    3.回调

    package com.jun.web.enhancer;
    
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    public class HelloWorldInterceptor implements MethodInterceptor {
        /**
         *
         * 方法描述 当对基于代理的方法回调时,在调用原方法之前会调用该方法
         * 拦截对目标方法的调用
         *
         * @param obj 代理对象
         * @param method 拦截的方法
         * @param args 拦截的方法的参数
         * @param proxy 代理
         * @return
         * @throws Throwable
         */
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            Object result = null;
            try {
                //前置通知
                before();
                result = proxy.invokeSuper(obj, args);
                //后置通知
                after();
            } catch (Exception e) {
                //异常通知
                exception();
            } finally {
                //方法返回前通知
                beforeReturning();
            }
    
            return result;
        }
    
        private void before() {
            System.out.println("before method invoke...");
        }
        private void after() {
            System.out.println("after method invoke...");
        }
        private void exception() {
            System.out.println("exception method invoke...");
        }
        private void beforeReturning() {
            System.out.println("beforeReturning method invoke...");
        }
    }

    4.代理

    package com.jun.web.enhancer;
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;
    
    import java.lang.reflect.Method;
    
    //创建Enhancer增强代理类的回调ProxyFactory类
    public class ProxyFactory  {
    
        //要代理的真实对象
        private Object obj;
    
        public Object createProxy(Object target) {
            Enhancer enhancer = new Enhancer();
            //设置代理目标
            enhancer.setSuperclass(target.getClass());
            //设置单一回调对象,在调用中拦截对目标方法的调用
            enhancer.setCallback(new HelloWorldInterceptor());
            //设置类加载器
            enhancer.setClassLoader(target.getClass().getClassLoader());
    
            return enhancer.create();
        }
    
    }

    5.测试

    package com.jun.web.enhancer;
    
    public class EnhancerTest {
        public static void main(String[] args) throws Exception {
            //将要被代理的对象
            HelloWorld hello = new HelloWorld();
            //代理
            ProxyFactory proxy = new ProxyFactory();
            //
            HelloWorld world = (HelloWorld)proxy.createProxy(hello);
            String result = world.say(false);
            System.out.println(result);
        }
    }

    6.效果

    Connected to the target VM, address: '127.0.0.1:60279', transport: 'socket'
    before method invoke...
    Hello Student
    exception method invoke...
    beforeReturning method invoke...
    null
    Disconnected from the target VM, address: '127.0.0.1:60279', transport: 'socket'

    三:其他回调

    1.FixedValue

      net.sf.cglib.proxy.FixedValue:为提高性能,FixedValue回调对强制某一特定方法返回固定值。

    package com.jun.web.enhancer;
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.FixedValue;
    
    public class FixedValueTest {
        public static void main(String[] args) throws Exception {
            HelloWorld hello = new HelloWorld();
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(hello.getClass());
            //设置单一回调对象,在调用中拦截对目标方法的调用
            enhancer.setCallback(new FixedValue() {
                @Override
                public Object loadObject() throws Exception {
                    return "FixedValue";
                }
            });
            //设置类加载器
            enhancer.setClassLoader(hello.getClass().getClassLoader());
    
            HelloWorld world = (HelloWorld)enhancer.create();
            String result = world.say(false);
            System.out.println(result);
        }
    }

    2.效果

    Connected to the target VM, address: '127.0.0.1:60379', transport: 'socket'
    Disconnected from the target VM, address: '127.0.0.1:60379', transport: 'socket'
    FixedValue
    
    Process finished with exit code 0

    3.NoOp

      net.sf.cglib.proxy.NoOp:NoOp回调把对方法调用直接委派到这个方法在父类中的实现(也可以理解成真实对象直接调用方法);

    package com.jun.web.enhancer;
    
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.NoOp;
    
    public class NoopTest {
        public static void main(String[] args) throws Exception {
            HelloWorld hello = new HelloWorld();
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(hello.getClass());
            enhancer.setCallback(NoOp.INSTANCE);
            enhancer.setClassLoader(hello.getClass().getClassLoader());
            HelloWorld obj = (HelloWorld)enhancer.create();
            System.out.println(obj.say(true));
        }
    }

    4.效果

    Disconnected from the target VM, address: '127.0.0.1:60418', transport: 'socket'
    Hello Student
    回答正确!
    
    Process finished with exit code 0

    5.其他的回调

      net.sf.cglib.proxy.LazyLoader:当实际的对象需要延迟装载时,可以使用LazyLoader回调。一旦实际对象被装载,它将被每一个调用代理对象的方法使用;
      net.sf.cglib.proxy.Dispatcher:Dispathcer回调和LazyLoader回调有相同的特点,不同的是,当代理方法被调用时,装载对象的方法也总要被调用;
      net.sf.cglib.proxy.ProxyRefDispatcher:ProxyRefDispatcher回调和Dispatcher一样,不同的是,它可以把代理对象作为装载对象方法的一个参数传递;

    四:CallbackFilter回调

    1.说明

      net.sf.cglib.proxy.CallbackFilter允许我们在方法层设置回调(callback),根据我们对方法处理的需求设置不同的回调;如下有一个类Hello,里面有两个方法save和update,save方法需要做前置和后置处理,但是update方法不需要:

    2.Hello

    package com.jun.web.enhancer;
    
    public class Hello {
        public String save() {
            System.out.println("save...");
            return "save";
        }
        public String update() {
            System.out.println("update...");
            return "update";
        }
    }

    3.

    package com.jun.web.enhancer;
    
    
    
    
    import org.springframework.cglib.proxy.CallbackFilter;
    
    import java.lang.reflect.Method;
    
    public class CallBackFilterTest implements CallbackFilter {
        /**
         * 方法返回的值是和callback回调接口数组一一对应的数组下标
         */
        @Override
        public int accept(Method method) {
            String name = method.getName();
            if("save".equals(name)) {
                return 0;
            }
            return 1;
        }
    }

    4.测试

    package com.jun.web.enhancer;
    
    
    import org.springframework.cglib.proxy.Callback;
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.NoOp;
    
    public class CallbackFilterMainTest {
        public static void main(String[] args) throws Exception {
            Hello hello = new Hello();
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(hello.getClass());
            enhancer.setCallbackFilter(new CallBackFilterTest());
            //创建各个目标代理方法的回调,回调的顺序要与过滤器索引一致
            Callback[] callbacks = new Callback[] {new HelloWorldInterceptor(), NoOp.INSTANCE};
            //设置单一回调对象,在调用中拦截对目标方法的调用
            enhancer.setCallbacks(callbacks);
            Hello obj = (Hello)enhancer.create();
    
            System.out.println(obj.update());
            System.out.println("=============");
            System.out.println(obj.save());
        }
    }

    5.效果

    Connected to the target VM, address: '127.0.0.1:60873', transport: 'socket'
    update...
    update
    =============
    before method invoke...
    Disconnected from the target VM, address: '127.0.0.1:60873', transport: 'socket'
    save...
    after method invoke...
    beforeReturning method invoke...
    save
    
    Process finished with exit code 0
  • 相关阅读:
    pip安装指定版本的package
    学习 git基础命令
    美剧命名规则
    Mac OS X中bogon的处理
    学习Maven之Maven Clean Plugin
    学习Maven之Cobertura Maven Plugin
    博客园markdown代码块支持的语言
    学习Maven之Maven Surefire Plugin(JUnit篇)
    C# Invoke或者BeginInvoke的使用
    LINQ to SQL语句(20)之存储过程
  • 原文地址:https://www.cnblogs.com/juncaoit/p/11401259.html
Copyright © 2011-2022 走看看