手机版 欢迎访问it开发者社区(www.mfbz.cn)网站

当前位置: > 开发

动态代理

时间:2021/5/21 3:39:34|来源:|点击: 次

JDK自带的代理模式

JDK自带的代理方式是需要实现invocationHandler接口,实现invoke的方法

共有的接口

public interface IUser {
    void talk();
}

委托类

public class User implements IUser{
    @Override
    public void talk() {
        /**
         * 委托类
         * 实现了接口Iuser中的talk方法
         */

                System.out.println("doing User.talk");
    }
}

代理辅助类

public class UserProxy implements InvocationHandler  {
    private Object object;

    public UserProxy(Object o) {
        this.object = o;
    }

    /**
     * 实现动态代理就需要实现InvocationHandler的invoke方法,有三个参数
     *
     * @param proxy:代理对象
     * @param method:调用的方法
     * @param args:改方法的参数
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //代理类提供委托类提供的功能,也可以提供自己特有的功能
        System.out.println("doing UserProxy.invoke");
        //调用委托类提供的方法
        method.invoke(object, args);
        System.out.println("doing UserProxy.invoke end");
        return null;
    }
    }

实现代理

 public static void main(String[] args) throws Throwable {
        //产生代理对象
       IUser iUser= (IUser)Proxy.newProxyInstance(User.class.getClassLoader(),new Class[]{IUser.class},new UserProxy(new User()));
        iUser.talk();
        
    }

打印结果
在这里插入图片描述
通过对打印结果的观察,当前的代理类调用talk方法,调用到代理辅助类UserProxy中的invoke方法,还调用到了委托类的talk实现

JVM是如何自动实现invoke方法的调用呢?

        //看看JDK生成的自动代理类
        System.setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
//        通过执行后查看,JVM生成了一个$Proxy0.class文件,源码如下-----$Proxy0.class
//        $Proxy0的定义中可知,确实实现了IUser接口。和代理模式下的代理是完全一致

自动实现的代理类

CGLib动态代理

代理提供了一种可扩展机制来控制被代理对象的访问,就是对象的访问做了一层封装
当代理没有接口的类,此时Proxy和InvocationHandler机制不能使用了(JDK自带的代理模式的使用必须需要有接口的),此时可以使用CGLib库,采用底层字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截父类所有方法的调用,采用横切的逻辑。Spring AOP(横向切面)的技术技术就是使用动态代理

需要引入第三方库

      <!--CGLib-->
      <dependency>
          <groupId>cglib</groupId>
          <artifactId>cglib</artifactId>
          <version>3.2.2</version>
      </dependency>

委托父类

public class CGLibSuper {
    public void doing() {
        System.out.println("CGLibSuper.doing");
    }
}

代理辅助类

/**
 * 通过已有的类产生代理类时
 * 在当前辅助类需要实现MethodInterceptor接口
 */
public class CGLibProxy  implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();
    
    public <T> T getProxy(Class<T> clazz) {
        //设置需要创建子类的类
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        //通过字节码动态的创建子类实例
        return (T)enhancer.create();
    }
    
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("CGLibProxy doing");
        //拦截到父类响应的方法
        Object o1 = methodProxy.invokeSuper(o, objects);
        System.out.println("CGLibProxy doing end");
        return o1;
    }
}

实现代理

    public static void main(String[] args) {
        CGLibProxy cgLibProxy = new CGLibProxy();
        //动态产生的CGLibSuper的子类实例
        CGLibSuper proxy = cgLibProxy.getProxy(CGLibSuper.class);
        proxy.doing();
    }

打印结果
在这里插入图片描述

通过打印结果可知,当前产生的代理类调用相应的方法(doing),会被代理辅助类中的intercept方法拦截,在该方法中可以实现扩展,器也能调用到父类中的相应方法

两种代理模式的区别

jdk自带的代理模式需要接口
CGLib代理模式不需要接口,也给对象的访问做了一层封装

上一篇:sleep和wait的区别 下一篇:数组排序

Copyright © 2002-2019 某某自媒体运营 版权所有