java代理

java代理

为什么使用代理

代理分类

注:代理一定要实现被代理类中的方法,于是我们经常会看见把代理和被代理中的方法抽象为一个借口,增加了一个约束。

准备工作

接口:

public interface ProxyInterface {
    void doAction();
}

实现类:

public class Action implements ProxyInterface {
    @Override
    public void doAction() {
        System.out.println("do action ...");
    }
    public void test(){
        System.out.println("action test ...");
    }
    @TestAnnotation
    public final String test1(){
        System.out.println("action test string ...");
        return "hello cglib";
    }
    @TestAnnotation
    public final String test1(String s){
        System.out.println(s);
        System.out.println("action test string ...");
        return "hello cglib";
    }
 }

自定义注解:

@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TestAnnotation {
}

静态代理

静态需实现接口,或者继承父类,保证与呗代理类有相同的方法签名。

定义代理类,继承接口:

public class ActionProxy implements ProxyInterface {
    private ProxyInterface proxy;

    public ActionProxy(ProxyInterface proxy){
        this.proxy = proxy;
    }

    @Override
    public void doAction() {
        System.out.println("before action ...");
        proxy.doAction();
        System.out.println("after action ...");
    }
}
public class Exec {

    public static void main(String[] args) {
        Action action = new Action();
        ActionProxy actionProxy = new ActionProxy(action);
        actionProxy.doAction();
    }
}
run result:
before action ...
do action ...
after action ...

动态代理

jdk动态代理

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

public class MyInvocationHandler<T> implements InvocationHandler {
    /**
     * 目标对象
     */
    private T target;

    public MyInvocationHandler(){

    }

    public MyInvocationHandler(T target){
        this.target = target;
    }

    /**
     * 获取代理对象
     * @param <T>
     * @return
     */
    public <T> T getProxy(){
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before action do do do ....");
        return method.invoke(target,args);
    }
}

创建代理类有以下几种实现方式:

public class Exec {
    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // 保存字节码
        System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

        Action action = new Action();
        MyInvocationHandler handler = new MyInvocationHandler<ProxyInterface>(action);

        // 分步
        Class<?> proxyClass = Proxy.getProxyClass(Action.class.getClassLoader(), Action.class.getInterfaces());
//        Class<?> proxyClass = Proxy.getProxyClass(Action.class.getClassLoader(), new Class<?>[]{ProxyInterface.class});
        Constructor<?> constructor = proxyClass.getConstructor(InvocationHandler.class);
        ProxyInterface o = (ProxyInterface) constructor.newInstance(handler);
        o.doAction();

        // 直接创建代理类
        ProxyInterface jdkProxy = (ProxyInterface) Proxy.newProxyInstance(Action.class.getClassLoader(), Action.class.getInterfaces(), handler);
        jdkProxy.doAction();

        // java8 lambam写法
        ProxyInterface jdkProxy1 = (ProxyInterface) Proxy.newProxyInstance(
                Action.class.getClassLoader(),
                Action.class.getInterfaces(),
                (proxy, method, params) -> {
                    System.out.println("before...");
                    Object invoke = method.invoke(action, params);
                    System.out.println("after...");
                    return invoke;
                }
        );
        jdkProxy1.doAction();


        ProxyInterface proxy  = new MyInvocationHandler<ProxyInterface>(action).getProxy();
        proxy.doAction();

    }
}

cglib动态代理

简述

并不要求委托类必须实现接口,底层采用asm字节码生成框架生成代理类的字节码。

cglib动态代理需要有回调方法,继承自Callback接口,cglib 实现了6种回调方法(callback):

  • FixedValue
  • InvocationHandler
  • LazyLoader
  • MethodInterceptor
  • Dispatcher
  • NoOp

代理实现:

/**
 * 查找A上的所有非final 的public类型的方法定义;
 * 将这些方法的定义转换成字节码;
 * 将组成的字节码转换成相应的代理的class对象;
 * 实现 MethodInterceptor接口,用来处理 对代理类上所有方法的请求(这个接口和JDK动态代理InvocationHandler的功能和角色是一样的)
 */
public class Exec {
    public static void main(String[] args) {
        Action action = new Action();

        CglibInterceptor cglibInterceptor = new CglibInterceptor();
        // cglib加强器,用来创建动态代理
        Enhancer enhancer = new Enhancer();
        // 设置要动态代理的类
        enhancer.setSuperclass(Action.class);
        // 设置回调,相当于所有方法都要回调
        enhancer.setCallback(cglibInterceptor);

        enhancer.setCallback(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
                System.out.println("before proxy");
//                method.invoke(action,objects);
                // 代理类的父类
                method.invoke(proxy.getClass().getSuperclass().newInstance(),args);
                System.out.println("after proxy");
                return null;
            }
        });
        // 拦截器过滤
        CallbackHelper callbackHelper = new CallbackHelper(action.getClass(), null) {
            @Override
            protected Object getCallback(Method method) {
//                if(method.getDeclaringClass() != Object.class && method.getReturnType() == String.class) {
//                    return cglibInterceptor;
//                }
                Annotation annotation = method.getAnnotation(TestAnnotation.class);
                if(annotation != null){
                    return cglibInterceptor;
                }
                return NoOp.INSTANCE;
            }
        };
        enhancer.setCallbackFilter(callbackHelper);
        enhancer.setCallbacks(callbackHelper.getCallbacks());
        Action proxy = (Action) enhancer.create();

//        proxy.doAction();
        proxy.test1();
    }
}

源码浅析:
Enhancer.createHelper()

   private Object createHelper() {
        this.preValidate();
		// 一级缓存使用的key
        Object key = KEY_FACTORY.newInstance(this.superclass != null ? this.superclass.getName() : null, ReflectUtils.getNames(this.interfaces), this.filter == ALL_ZERO ? null : new WeakCacheKey(this.filter), this.callbackTypes, this.useFactory, this.interceptDuringConstruction, this.serialVersionUID);
        this.currentKey = key;
        Object result = super.create(key);
        return result;
    }

CallbackHelper中用到Enhancer.getMethods()

private static void getMethods(Class superclass, Class[] interfaces, List methods, List interfaceMethods, Set forcePublic) {
    ReflectUtils.addAllMethods(superclass, methods);
    List target = interfaceMethods != null ? interfaceMethods : methods;
    if (interfaces != null) {
        for(int i = 0; i < interfaces.length; ++i) {
            if (interfaces[i] != Factory.class) {
                ReflectUtils.addAllMethods(interfaces[i], target);
            }
        }
    }

    if (interfaceMethods != null) {
        if (forcePublic != null) {
            forcePublic.addAll(MethodWrapper.createSet(interfaceMethods));
        }

        methods.addAll(interfaceMethods);
    }
    // 过滤static修饰的方法
    CollectionUtils.filter(methods, new RejectModifierPredicate(8));
    // 过滤不可见方法,private/与目标类不在同一个包中的方法
    CollectionUtils.filter(methods, new VisibilityPredicate(superclass, true));
	// 过滤重复方法
    CollectionUtils.filter(methods, new DuplicatesPredicate());
    // 过滤final修饰方法
    CollectionUtils.filter(methods, new RejectModifierPredicate(16));
}

java.lang.reflect.Modifier的静态属性对应如下:

  • PUBLIC: 1
  • PRIVATE: 2
  • PROTECTED: 4
  • STATIC: 8
  • FINAL: 16
  • SYNCHRONIZED: 32
  • VOLATILE: 64
  • TRANSIENT: 128
  • NATIVE: 256
  • INTERFACE: 512
  • ABSTRACT: 1024
  • STRICT: 2048
    Enhancer会过滤final/static/private修饰的/重复的方法/默认修饰符且与目标类不在同一个包中的方法。

CGLIB动态代理与JDK动态区别

  1. java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。
  2. cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。 因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值