0
点赞
收藏
分享

微信扫一扫

Spring动态代理原理是什么?

IT影子 2022-04-03 阅读 48
spring

动态代理的两种模式

  1.        jdk动态代理    //基于实现接口
  2.        Cglib动态代理   //基于方法的继承

????????啥东西

这就不得不提到 静态代理了: 说得高大上,其实就是写一个增强类继承被增强类,

实现被增强类的同时,也可以在其中添加一些代码,增强了被增强类

但问题是:静态代理想要再增强,无非就是修改代码;或者再写一个类去增强那个增强类。

在实际开发中,这是一种很蠢的行为;跟套娃一样不说,代码冗余还越来越多。

动态代理

Spring提供了完美的动态代理,我们来看看其原理:

代码:jdk动态代理 :针对实现接口的类进行增强

public interface Subject { //公共接口
    void buyHouse();
}
public class RealSubject implements Subject{
    @Override
    public void buyHouse() {
        System.out.println("买房子");
    }
}

买房接口和买家买房实现类

jdk动态代理类:

public class JDKProxyFactory { //jdk动态代理工厂

    public static Object getProxyObj(Object obj){ //目标对象


        /**
         * ClassLoader loader,       类加载
         * Class<?>[] interfaces,    目标对象实现接口
         * InvocationHandler h       调用拦截器
         */

        //获取类加载器
        ClassLoader loader = obj.getClass().getClassLoader();
        //获取目标对象实现的接口
        Class<?>[] interfaces = obj.getClass().getInterfaces();
        //定义调用拦截器
        InvocationHandler handler = new InvocationHandler() {
            //当目标对象的方法调用的时候会回调这个方法

            /**
             *
             * @param proxy     代理对象
             * @param method    目标对象的方法
             * @param args      目标对象的参数
             * @return
             * @throws Throwable
             */
            @Override
public Object invoke(Object proxy, Method method, Object[] args)
 throws Throwable {
                System.out.println("找房源....");
                //调用目标对象的方法!!!!
                //参数1:类的对象  参数2:方法的参数
                Object invoke = method.invoke(obj, args);
                System.out.println("办理手续....");
                return invoke;  //这里的返回值就是目标对象的返回值
            }
        };
Object proxyObj = Proxy.newProxyInstance(loader, interfaces, handler);
        return proxyObj;
    }

测试类: 

public class JDKProxyTest {
    @Test
    public void test01(){
        //创建目标对象
        Subject realSubject = new RealSubject();
        //realSubject.buyHouse();

        //通过代理工厂创建代理对象
        Subject proxyObj = (Subject) JDKProxyFactory.getProxyObj(realSubject);
        //把方法传给代理类
        proxyObj.buyHouse();
        //通过代理类调用实际上调用的是invoke()

        //代理对象和目标对象的关系?    共同实现了同一个接口(兄弟)
        System.out.println(proxyObj instanceof  Subject);//true
        System.out.println(proxyObj instanceof  RealSubject);//false


    }

关键问题:为什么method就是被增强方法呢?为啥调用invoke就进行了增强呢?为什么通过代理类调用方法时会被拦截并且进入invoke()方法?

1:因为将对象交由jdk动态代理了,其通过反射可以获取到类的所有信息;通过增强的对象调用原有的方法,不会执行原有的方法,而是执行代理对象的方法。

2:而代理类调用拦截器拦截方法 InvocationHandler,将增强方法对象调用的原有方法的操作拦截下来,并进行增强。InvocationHandler 重写了invoke()所以被拦截后一定会执行invoke()方法

invoke(Object proxy, Method method, Object[] args) //这三个参数也是通过反射获取到的。

(通过反射获取的方法实例,方法接口对应的方法实例,对象方法的参数数组)

3.Object invoke = method.invoke(obj, args) (类对象的实例,方法的参数数组)

底层调用了native方法:可以看出:返回方法有三个参数

 public Object invoke(Object var1, Object[] var2) throws IllegalArgumentException, InvocationTargetException {
        if (++this.numInvocations > ReflectionFactory.inflationThreshold()
 && !ReflectUtil.isVMAnonymousClass(this.method.getDeclaringClass())) 
{
            MethodAccessorImpl var3 = (MethodAccessorImpl)(
new MethodAccessorGenerator()).generateMethod
(this.method.getDeclaringClass(), this.method.getName(),
 this.method.getParameterTypes(), this.method.getReturnType(), 
this.method.getExceptionTypes(), this.method.getModifiers());
            this.parent.setDelegate(var3);
        }

        return invoke0(this.method, var1, var2);
    }
Object proxyObj = Proxy.newProxyInstance(loader, interfaces, handler)将类加载器,接口参数,拦截器(方法增强后)  一并返回给调用增强方法的类

举报

相关推荐

0 条评论