java代理的使用尝试过程Proxy.newProxyInstance

版权声明:本文为博主原创文章,请尊重劳动成果,转载注明一下出处。 https://blog.csdn.net/zq1994520/article/details/81073642

Proxy.newProxyInstance是实现java对象的动态代理的方法,他的三个参数loader、 interfaces、h分别代表是需求代理的接口的加载器、 代理接口列表、this。注意,只能代理接口,不能代理类或者抽象类。

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

1、第一次测试我尝试着动态代理能不能实现类似after,before的功能,用来记录支付的次数或者其他功能。

根据上图我建立一个测试接口:Pay

public interface Pay {
    boolean pay();
}

 再新建一个Person类,实现Pay接口:

public class Person implements Pay {
    @Override
    public boolean pay() {
        System.out.println("支付中。。。");
        return true;
    }
}

再新建一个代理类:

public class PayProxy<T> {
    public PayProxy() {
    }

    private static int count = 0;
    public void before(){
        count++;
        System.out.println("快要支付了");
    }

    public void after(){
        System.out.println("支付完成, 已完成" + count + "次");
    }
    /**
     * @Description <p> 动态代理,通过接口获取实现接口的对象的实例</p>
     * @FunName <p></p>
     * @Param {serviceInterface : 需要代理的接口class}
     * @Param {u : 实现serviceInterface接口的类,也就是这次我门要来计算次数}
     */

    public T getRemoteProxyObj(final Class<T> serviceInterface, Class<? extends T> u) {
        return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class[]{serviceInterface},
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        before();
                        Object obj = method.invoke(u.getConstructor().newInstance(), args);
                        after();
                        return obj;
                    }
                });
    }
}

编写测试主类

public class PayTest {
    public static void main(String[] args) throws IOException {
        
        PayProxy<Pay> payProxy = new PayProxy<Pay>();
        Pay pay = payProxy.getRemoteProxyObj(Pay.class, Person.class);
        pay.pay();
    }
}

测试结果:

快要支付了
支付中。。。
支付完成, 已完成1次

分析:

关键代码

                         before(); 
                        Object obj = method.invoke(u.getConstructor().newInstance(), args);  //这儿调用的是Person的pay方法,该代理类是类似监听器,监听所有实现serviceInterface接口的类调用该接口里面的方法(pay方法)。但是这儿有个不完美的地方,熟悉的人可能发现,我这儿是在调用pay方法之后才让Pay接口的实现类Person实例化,有人可能会说,为什么不通过参数传递呢,下面我就来第二个。
                        after();

2、同样的实现那个功能,但是我们修改代理类如下:

public class PayProxy<T> {
    public PayProxy() {
    }

    private static int count = 0;
    public void before(){
        count++;
        System.out.println("快要支付了");
    }

    public void after(){
        System.out.println("支付完成, 已完成" + count + "次");
    }
    /**
     * @Description <p> 动态代理,通过接口获取实现接口的对象的实例</p>
     * @FunName <p></p>
     * @Param {serviceInterface : 需要代理的接口class}
     * @Param {u : 实现serviceInterface接口的类,也就是这次我门要来计算次数}
     */

    public T getRemoteProxyObj(final Class<T> serviceInterface,@NotNull T u) {
        return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class[]{serviceInterface},
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        before();
                        Object obj = method.invoke(u, args);
                        after();
                        return obj;
                    }
                });
    }
}

同样修改测试类:

public class PayTest {
    public static void main(String[] args) throws IOException {
        
        PayProxy<Pay> payProxy = new PayProxy<Pay>();
        Person person = new Person();
        Pay pay = payProxy.getRemoteProxyObj(Pay.class, person);
        pay.pay();
    }
}

经多测试一样的能结果。

3、我想通过它实现一个匿名类:

这次我们不需要Person类了。只需要修改代理类

public class PayProxy<T> {

    public Object doSome(){
        System.out.println("这儿需要作的处理");
        return false;
    }
    /**
     * @Description <p> 动态代理,通过接口获取实现接口的对象的实例</p>
     * @FunName <p></p>
     * @Param {serviceInterface : 需要代理的接口class}
     * @Param {u : 实现serviceInterface接口的类,也就是这次我门要来计算次数}
     */

    public T getRemoteProxyObj(final Class<T> serviceInterface) {
        return (T) Proxy.newProxyInstance(serviceInterface.getClassLoader(), new Class[]{serviceInterface},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        Object object = doSome(); // 这里面可以传递参数给doSome,方法里面的参数值是args。比如doSome(args)
                        return object;
                    }
                });
    }
}

测试类修改:

public class PayTest {
    public static void main(String[] args) throws IOException {
        
        PayProxy<Pay> payProxy = new PayProxy<Pay>();
        Pay pay = payProxy.getRemoteProxyObj(Pay.class);
        pay.pay();
    }
}

测试结果:

这儿需要作的处理

代理使用心得:

Proxy.newProxyInstance(代理对象类加载器,生成类需要实现的接口s,InvocationHandler是的实现(统一的给需要实现的接口统一的编写实现方式,Method和arg[]两个参数判断是那个方法) )。在Proxy.newProxyInstance中还可以在method.invoke执行前后做些准备工作,类似拦截器,监听器,junit过程。

另外,能够使用Proxy.newProxyInstance的都能使用CGLib来实现,CGLib生成代码更加彻底。它一个强大的、高性能的代码生成库,这儿就不详细赘述。

猜你喜欢

转载自blog.csdn.net/zq1994520/article/details/81073642
今日推荐