代理

瘦欲@ 提交于 2020-04-06 02:17:46

动态代理

//接口类
public interface PersonBehavior {

    void talk();

    void jump();
}
//实现类(被代理类)
public class DefaultPersonBehavior implements PersonBehavior {

    @Override
    public void talk() {
        System.out.println("We can talk");
    }

    @Override
    public void jump() {
        System.out.println("We can jump");
    }
}
public class PersonBehaviorHandler implements InvocationHandler {

    private Object target;

    public PersonBehaviorHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("We can do anything before ...");
        Object result = method.invoke(target, args);
        return result;
    }
}
//super man proxy
PersonBehavior superManBehavior = new DefaultSuperManBehavior();
//获取superManBehavior相关的handler
PersonBehaviorHandler superManHandler = new PersonBehaviorHandler(superManBehavior);
//获取代理对象
PersonBehavior superManProxy = (PersonBehavior) Proxy.newProxyInstance(PersonBehavior.class.getClassLoader(), new Class<?>[]{PersonBehavior.class}, superManHandler);
superManProxy.jump();

打印结果:We can do anything before ...
                  We can super jump

@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
    Objects.requireNonNull(h);

    final Class<?>[] intfs = interfaces.clone();
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    /*
     * Look up or generate the designated proxy class.
     */
    Class<?> cl = getProxyClass0(loader, intfs);  //这边生成了代理类

    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }

        final Constructor<?> cons = cl.getConstructor(constructorParams); //获取了构造器
        final InvocationHandler ih = h;
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
        }
        return cons.newInstance(new Object[]{h}); //生成了代理对象
    } catch (IllegalAccessException|InstantiationException e) {
        throw new InternalError(e.toString(), e);
    } catch (InvocationTargetException e) {
        Throwable t = e.getCause();
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        } else {
            throw new InternalError(t.toString(), t);
        }
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString(), e);
    }
}

 

实际使用动态代理的时候,jdk为我们的生成了一个叫$Proxy0(这个名字后面的0是编号,有多个代理类会一次递增)的代理类,这个类文件时放在内存中的,我们在创建代理对象时,就是通过反射获得这个类的构造方法,然后创建的代理实例。

我们可以对InvocationHandler看做一个中介类,中介类持有一个被代理对象,在invoke方法中调用了被代理对象的相应方法。通过聚合方式持有被代理对象的引用,把外部对invoke的调用最终都转为对被代理对象的调用。

代理类调用自己方法时,通过自身持有的中介类对象来调用中介类对象的invoke方法,从而达到代理执行被代理对象的方法。也就是说,动态代理通过中介类实现了具体的代理功能

 

总结

生成的代理类:$Proxy0 extends Proxy implements Person,我们看到代理类继承了Proxy类,所以也就决定了java动态代理只能对接口进行代理,Java的继承机制注定了这些动态代理类们无法实现对class的动态代理。

参考: https://www.cnblogs.com/gonjan-blog/p/6685611.html

CGLIB代理

  • CGLIB 原理:动态生成一个要代理类的子类,子类重写要代理的类的所有不是final的方法。在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。它比使用java反射的JDK动态代理要快。
  • CGLIB 底层:使用字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
  • CGLIB缺点:对于final方法,无法进行代理

为什么使用CGlib

  • CGLIB代理主要通过对字节码的操作,为对象引入间接级别,以控制对象的访问。我们知道Java中有一个动态代理也是做这个事情的,那我们为什么不直接使用Java动态代理,而要使用CGLIB呢?答案是CGLIB相比于JDK动态代理更加强大,JDK动态代理虽然简单易用,但是其有一个致命缺陷是,只能对接口进行代理。如果要代理的类为一个普通类、没有接口,那么Java动态代理就没法使用了。

注意点

  • CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类。

例子

 

//被代理对象
public class TargetClass {

    public String sayHello() {
        System.out.println("Hello everybody.");
        return "Hello";
    }

    public String sayGoodBye() {
        System.out.println("GoodBye everyone;");
        return "GoodBye";
    }
}
//方法拦截器
public class TargetInterceptor implements MethodInterceptor {

    /**
     * @param targetObj 目标对象
     * @param method 目标方法
     * @param params 参数
     * @param methodProxy CGlib方法代理对象
     */
    @Override
    public Object intercept(Object targetObj, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
        System.out.println("Before invoke");
        Object result = methodProxy.invokeSuper(targetObj, params);
        System.out.println("After invoke");
        return result;
    }
}
public class CglibTest {

    public static void main(String[] args) {

        //Enhancer是一个字节码增强器,它可以方便的对你要增强的类进行扩展
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(TargetClass.class);
        enhancer.setCallback(new TargetInterceptor());
        TargetClass targetObjectCglibProxy = (TargetClass) enhancer.create();
        targetObjectCglibProxy.sayHello();
    }
}
  • CGlib的 回调过滤器CallbackFilter 和 FixedValue

    package com.trip.study.proxy.cglib;
    
    import org.springframework.cglib.proxy.CallbackFilter;
    
    import java.lang.reflect.Method;
    
    public class TargetMethodCallBackFilter implements CallbackFilter {
    
    
        @Override
        public int accept(Method method) {
            if ("sayHello".equalsIgnoreCase(method.getName())) {
                System.out.println("CallBackFilter:sayHello" + 0);
                return 1;
            }
            //一个方法不可以同时匹配两次,以第一个匹配的为准
            if ("sayHello".equalsIgnoreCase(method.getName())) {
                System.out.println("CallBackFilter:sayHello2" + 0);
                return 2;
            }
            if ("sayGoodBye".equalsIgnoreCase(method.getName())) {
                System.out.println("CallBackFilter:sayGoodBye" + 1);
                return 0;
            }
            return 0;
        }
    }
    package com.trip.study.proxy.cglib;
    
    import org.springframework.cglib.proxy.FixedValue;
    
    public class TargetResultFixed implements FixedValue {
    
        @Override
        public Object loadObject() throws Exception {
            System.out.println("lock result");
            return "what's your name ?";
        }
    }
    package com.trip.study.proxy.cglib;
    
    import org.springframework.cglib.proxy.Callback;
    import org.springframework.cglib.proxy.CallbackFilter;
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.NoOp;
    
    public class TestCallBackFilter {
    
        public static void main(String[] args) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(TargetClass.class);
            CallbackFilter callbackFilter = new TargetMethodCallBackFilter();
            //NoOp.INSTANCE:这个NoOp表示no operator,即什么操作也不做,代理类直接调用被代理的方法不进行拦截
            Callback noOp = NoOp.INSTANCE;
            //callback方法拦截器
            Callback callback = new TargetInterceptor();
            //我们还可以加入结果拦截器,无论结果返回什么,都会返回what's your name ?
            Callback callbackResult = new TargetResultFixed();
            //noOp对应TargetMethodCallBackFilterreturn 0(在数组中的下标),同理callback对应的是1,callbackResult对应的是2
            Callback[] callbacks = {noOp, callback, callbackResult};
            enhancer.setCallbackFilter(callbackFilter);
            enhancer.setCallbacks(callbacks);
            TargetClass proxy = (TargetClass) enhancer.create();
            String result = proxy.sayHello();
            System.out.println("Result ===== " + result);
        }
    }
  • 有问题欢迎指出,共同学习
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!