动态代理的两种实现方式

一,jdk动态代理:(下面说的构造器是个人理解比喻,不是构造方法)

首先需要知道一个类和一个接口Proxy,InvocationHandler

代理类建造方法

1.Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

参数:ClassLoader loader:任意对象的类加载器 .getClass().getClassLoader()

Class<?>[] interfaces:全部的接口,一般是接口实现类的实例.getClass().getInterfaces()

InvocationHandler h:代理类的构造器对象

代理类构造器

2.InvocationHandler接口只有一个方法:

Object invoke(Object proxy, Method method, Object[] args)

参数:Object proxy:指被代理的对象。

Method method:要调用的方法,一般固定语句使用method.invoke(代理对象类,参数).来调用需要调用的方法

Object[] args:方法调用时所需要的参数

我们需要的:

1.代理类构造器(类,创造代理的工具)(InvocationHandler的实现类,其invoke方法参数为固定的,其中method的invoke方法不是此invoke方法。由Proxy类使用反射调用,我们不需要调用)

2.代理类建造方法(方法,中介创建者):Proxy.newProxyInstance(代理接口的类加载器,代理接口,代理类构造器对象--就是1) 该方法可写在代理类构造器中

3.接口(房子)

4.实现接口的类 即被代理对象(房东)

使用步骤:

1.先创建代理类构造器(InvocationHandler接口的实现类),重写接口中invoke方法,

其中method.invoke(被代理的对象,参数),来调用需要调用的方法。我们可以在此上下增强原方法的功能

(就是代理对象被创建出来后,调用方法时,该method通过反射获取你的方法,可以method.getName()获取调用的方法名,使用method.invoke()调用该方法)

2.可以将代理类建造方法Proxy.newProxyInstance写在代理类构造器中,封装为getProxy方法,返回Object类型代理对象,使用时强转类型,这时参数为(任意对象.class.getClassLoader,接口(两种写法,一种是直接写接口.class,一种是实现类.class.getInterfaces()),代理类构造器(this))

public class ProxyInvocationHandler implements InvocationHandler {
    //被代理接口/对象
        private Object object;
        //测试是否为任意对象的类加载器都可以作为参数
        private User user = new User();

    //构造方法
    public ProxyInvocationHandler(Object object) {
        this.object = object;
    }

    public Object getProxy(){
            return Proxy.newProxyInstance(
                    user.getClass().getClassLoader(),
                    object.getClass().getInterfaces(),
                    this);
        }
        //反射方法,method可以获取被代理对象调用的方法,进行一些操作
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String name = method.getName();
            System.out.println("调用前,调用的方法为:"+name);
            Object res = method.invoke(object,args);
            System.out.println("调用后,调用的方法为:"+name);
        return res;
    }
}

3.测试类中

a.创建被代理对象。

b.创建代理类构造器,并将被代理对象传参给它。

c.使用代理类构造器创建代理类,因为得到的是Object类型,所以需要强转类型。

d.调用方法。

public class Test {
    public static void main(String[] args) {
        //被代理对象
        landlord landlord = new landlord();
        //代理类构造器
        ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler(landlord);
        //创建代理类
        Host host= (Host) proxyInvocationHandler.getProxy();

        host.sellHost();
    }
}

结果

调用前,调用的方法为:sellHost

房东卖房

调用后,调用的方法为:sellHost

Cglib动态代理

Cglib是针对实现类来代理的,被代理者不需要实现接口,它对目标类生成一个子类,并覆盖其中的方法,以实现方法的增强。

cglib的主要方法拦截接口 MethodInterceptor,需要用户自己实现:

public interface MethodInterceptor extends Callback {
    Object intercept(Object var1, Method var2, Object[] var3, MethodProxy var4) throws Throwable;
}


参数说明:

前三个参数与jdk中InvocationHandler中的Invoke相同:

Object var1:指被代理的对象。
Method var2:要调用的方法 
Object[] var3:方法调用时所需要的参数 

MethodProxy var4: JDK的java.lang.reflect.Method类的代理类,可以实现对源对象方法的调用。后面的例子将会帮助理解。

Enhancer:cglib主要的增强类,下面简单看下其中方法:

setSuperclass: 设置被代理的对象。

setCallback: 设置回调函数,一般为MethodInterceptor的实现类。

creat: 创建一个代理对象,你可以直接使用创建的代理对象调用原本的方法。

看个实例:

public class MyCglibInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("----------before----"+method.getName());
        Object o1 = methodProxy.invokeSuper(o, objects);
        System.out.println("----------after----"+method.getName());
        return o1;
    }
}


之前说了,cglib是创建一个子类,并覆盖目标类方法,所以我们调用方法时,是使用methodProxy.invokeSuper()。我们在每个方法之前之后都输出一些语句。

测试代码:

 

MyCglibInterceptor myCglibInterceptor=new MyCglibInterceptor();
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(myInterface.getClass());
        enhancer.setCallback(myCglibInterceptor);
        MyInterface res = (MyInterface) enhancer.create();
        res.getName();
        res.getAge();


结果:

----------before----getName
tom
----------after----getName
----------before----getAge
11
----------after----getAge

参考文档:

尚硅谷-Spring5框架最新版教程(idea版)_哔哩哔哩_bilibili

【狂神说Java】Spring5最新完整教程IDEA版通俗易懂_哔哩哔哩_bilibili

(3条消息) 动态代理-两种实现方式_wy9717的博客-CSDN博客_动态代理实现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值