文章目录

  • 1.JDK动态代理
  • 代码
  • 代码结构:
  • 总结
  • 2.Cglib动态代理
  • 代码
  • 3.总结


1.JDK动态代理

首先,我们需要明白的就是在jdk动态代理当中,需要明白的就是,为什么会有这样一个代理,那是因为当需要代理的方法越来越多的时候,这个时候就会增大麻烦量,于是就引出了JDK的动态代理。

代码

首先是书写对应的接口,以及你需要完成的任务对应的实现类
subject.interface

package com.example.qhb.Jdk;

public interface Subject {
    void request();
    void hell0();
}

RealSubject.class

package com.example.qhb.Jdk;

import jdk.internal.loader.AbstractClassLoaderValue;

public class RealSubect implements Subject {
    @Override
    public void request() {
        System.out.println("首先是发送对应的请求");
    }

    @Override
    public void hell0() {

        System.out.println("打一下招呼");
    }
}

接下来就是对应的书写代理类了,首先,我们需要明白的就是,在这里是需要使用到jdk的动态代理,而这个代理的好处就是可以一次性地将方法写入到放法invoke()中去,这个方法又是存在于接口InvocationHandler中的,所以在这里我们需要使用代理类来对这个接口进行实现:
JdkProxySubject.class

package com.example.qhb.Jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class JdkProxySubject implements InvocationHandler {

    //接下来就是引入需要执行定义的目标类
    private RealSubect realSubect;

    public JdkProxySubject(RealSubect realSubect) {
        this.realSubect = realSubect;
    }

    /*
     *invoke方法方法参数解析
     *Object proxy:指被代理的对象。
     *Method method:要调用的方法
     *Object[] args:方法调用时所需要的参数
     *InvocationHandler接口的子类可以看成代理的最终操作类。
     */

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before");
        Object result = null;
        try {
            //利用反射,动态地来反射方法,这就是动态代理和静态代理的区别
            result = method.invoke(realSubect, args);//如果这里面是要进行invoke()单个的
            //方法的话,仅仅只需要写上对应的方法
        } catch (Exception e) {
            System.out.println("ex:" + e.getMessage());
            throw e;
        } finally {
            System.out.println("after");
        }
        return result;

    }

}

接下来就是这个对应的Client,这里就是进行的测试

package ProxyDemoTest.Jdk;



import java.lang.reflect.Proxy;

/*首先,我们需要明白的就是在学习代理类的一个过程中,需要明白的就是需要
有客户端,还需要有接口
 */
public class Client {
    public static void main(String[] args) {
        /*
        newProxyInstance方法参数解析
        ClassLoader loader 方法参数解析
        class<?>[] interfaces 得到全部的接口
        InvocationHandler: 得到InvocationHandler接口的子类实例
         */
        Subject subject=(Subject)Proxy.newProxyInstance(Client.class.getClassLoader(),new Class[]{Subject.class},
                new JdkProxySubject(new RealSubect())) ;
        subject.hell0();
        subject.request();
    }


}

这里面对应的就是主要的代理进行的一个过程,如果看不懂的话可以进行源码的品读,里面对应的就是首先是对这个class 进行加载,然后是对这个Subject接口进行加载,接下来就是对这个new JdkProxySubject(new RealSubject())进行的一个实现。

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

        final Class<?> caller = System.getSecurityManager() == null
                                    ? null
                                    : Reflection.getCallerClass();

        /*
         * Look up or generate the designated proxy class and its constructor.
         */
        Constructor<?> cons = getProxyConstructor(caller, loader, interfaces);

        return newProxyInstance(caller, cons, h);
    }

运行结果:

java读取gbk文件 javac gbk_System

代码结构:

java读取gbk文件 javac gbk_代理类_02

总结

我们在subject接口中新增加了一个hello()方法,然后在RealSubject中对hello()方法进行实现,但是在代理类中,我们不需要再去为hello方法再去写一个代理方法,而是通过反射调用目标对象的方法,来动态的生成代理类。

  • 因为利用JdkProxySubject生成的代理类实现了接口,所以目标类中所有的方法在代理类中都有
  • 生成的代理类的所有方法都拦截了目标类的所有的方法。而拦截器中invoke方法的内容正好就是代理类的各个方法的组成体
  • 利用JDK代理方式必须有接口的存在。

2.Cglib动态代理

上文我们讲到了使用JDK的动态代理,但是当我们没有接口的时候,该怎么来进行呢,很简单,就是在对应的目标对象类中进行方法的编写

代码

package ProxyDemoTest.Cglib;

public class Client {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealSubject.class);
        enhancer.setCallback(new DemoMethodInterceptor());
        // 此刻,realSubject不是单纯的目标类,而是增强过的目标类
        RealSubject realSubject = (RealSubject) enhancer.create();
        realSubject.hello();
        realSubject.request();
    }
}
package ProxyDemoTest.Cglib;

import java.lang.reflect.Method;

public class DemoMethodIntercepter implements MethodIntercepter{
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("before in cglib");
        Object result = null;
        try{
            result = proxy.invokeSuper(obj, args);
        }catch (Exception e){
            System.out.println("get ex:"+e.getMessage());
            throw e;
        }finally {
            System.out.println("after in cglib");
        }
        return result;
    }
}
package ProxyDemoTest.Cglib;

public class RealSubject {
    public void request(){
        System.out.println("发送一个请求");
    }

    public void hello(){
        System.out.println("打个招呼");
    }
}

这里面的思想和jdk动态代理的思想其实是相似的,不同之处在于cglib需要自己去下载一个包,进行引入

3.总结

总的来说,jdk动态代理和Cglib动态代理都是围绕着客户进行的,你需要进行方法的写入,一般而言都是方法较多的时候,然后就可以根据这样的方法类,引入invoke()这个方法进行实现,接下来需要做的就是这句关键词:

Subject subject=(Subject)Proxy.newProxyInstance(Client.class.getClassLoader(),new Class[]{Subject.class},
                new JdkProxySubject(new RealSubect())) ;

HAHA,你学会(费)了吗,今天的学习就到这里吧,明怀我最近还是感觉有点点忙的,但还是不够自律,还是要认真完成任务,并且好好巩固知识才行呀,咱们加油!