为了账号安全,请及时绑定邮箱和手机立即绑定

在我的代理类中为每个方法执行 InvocationHandler 调用方法

在我的代理类中为每个方法执行 InvocationHandler 调用方法

饮歌长啸 2022-11-02 10:00:56
我已经实现了一个动态代理,以便在我的方法开始之前执行一些操作。现在我从代理类调用两个方法时遇到问题,这里是代码:动态代理类:public class IPageProxy implements InvocationHandler {    private Class <? extends IPage> screenClazz;    public IPageProxy(final Class <? extends IPage> screenClazz) {        this.screenClazz = screenClazz;    }    @SuppressWarnings("unchecked")    public static <T extends IPage> T getInstance(final Class<? extends IPage> type)            throws InstantiationException, IllegalAccessException {        List<Class<?>> interfaces = new ArrayList<>();        interfaces.addAll(Arrays.asList(type.getInterfaces()));        return (T) Proxy.newProxyInstance(                type.getClassLoader(),                findInterfaces(type),                new IPageProxy(type)             );    }    static Class<?>[] findInterfaces(final Class<? extends IPage> type) {        Class<?> current = type;        do {            final Class<?>[] interfaces = current.getInterfaces();            if (interfaces.length != 0) {                return interfaces;            }        } while ((current = current.getSuperclass()) != Object.class);        throw new UnsupportedOperationException("The type does not implement any interface");    }    @Override    public Object invoke(final Object proxy, final Method method, final Object[] args) throws InvocationTargetException,            IllegalAccessException, IllegalArgumentException, InstantiationException, ParserConfigurationException, XPathExpressionException, NoSuchFieldException, SecurityException {        // before method executed this code will be done        System.out.println("*   Dynamic proxy invoke method executed for " +  method.getName());        // Invoke original method        return method.invoke(screenClazz.newInstance(), args);    }}
查看完整描述

2 回答

?
郎朗坤

TA贡献1921条经验 获得超9个赞

发生的事情是,首先您只代理第一次调用,然后您在非代理类上调用 getShow(),这就是为什么您会得到您提到的结果。如果你想实现你提到的目标,你需要基于创建的实例而不是仅仅基于类创建另一个代理。


更新:我将提供示例代码,您可以粘贴到任何 java 文件中并执行它。在你看到 TODO 的地方,你可以根据你想要提供代理的方式放置你自己的逻辑。重要时刻见注。为了简化演示,我将所有类放在一个文件中。


import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.util.Arrays;

import java.util.List;


class Scratch {

    public static void main(String[] args) {

        try {

            IEventDesignDialog a  = proxy(EventDesignDialog.class);

            a.getEventType().getShow();

            a.getDateAndTimeDisplayFormat().getShow();

        } catch (InstantiationException | IllegalAccessException e) {

            e.printStackTrace();

        }

    }



    @SuppressWarnings("unchecked")

    private static <T extends IPage> T proxy(final Class<? extends IPage> type) throws InstantiationException, IllegalAccessException {

        return (T) IPageProxy.proxy(type);

    }

}

interface IPage{}

interface IEventDesignDialog extends IPage{

    IEventDesignDialog getShow();

    IEventDesignDialog getEventType();

    IEventDesignDialog getDateAndTimeDisplayFormat();

}

class EventDesignDialog implements IEventDesignDialog{


    public IEventDesignDialog getShow() {

        System.out.println("get show method invoked successfully");


        //NOTE: this will be treated as same proxy but not this

        return this;

    }


    public IEventDesignDialog getDateAndTimeDisplayFormat() {

        System.out.println("get date and time display format method invoked successfully");


        // NOTE: we supply some iinstance which will be proxied

        return new MyIEventDesignDialog();

    }


    public IEventDesignDialog getEventType() {

        System.out.println("get event type method invoked successfully");


        //NOTE: this will be treated as same proxy but not this

        return this;

    }


}

class IPageProxy implements InvocationHandler {


    private IPage instance;

    private List<Class<?>> interfaces;



    public IPageProxy(IPage instance, List<Class<?>> interfaces) {

        this.instance = instance;

        this.interfaces = interfaces;

    }


    @SuppressWarnings("unchecked")

    public static <T extends IPage> T proxy(final Class<? extends IPage> type)

            throws InstantiationException, IllegalAccessException {


        List<Class<?>> interfaces = Arrays.asList(type.getInterfaces());



        //TODO: get interfaces properly recursively

        return (T) Proxy.newProxyInstance(

                type.getClassLoader(),

                type.getInterfaces(),

                new IPageProxy(type.newInstance(), interfaces)

        );


    }


    @SuppressWarnings("unchecked")

    public static <T extends IPage> T proxy(T object) {


        //TODO: get interfaces properly recursively

        List<Class<?>> interfaces = Arrays.asList(object.getClass().getInterfaces());


        return (T) Proxy.newProxyInstance(

                object.getClass().getClassLoader(),

                object.getClass().getInterfaces(),

                new IPageProxy(object, interfaces)

        );


    }





    @Override

    public Object invoke(final Object proxy, final Method method, final Object[] args) throws Exception {


        // before method executed this code will be done

        System.out.println("*   Dynamic proxy invoke method executed for " +  method.getName());


        // Invoke original method

        Object invoke = method.invoke(instance, args);

        if (invoke == null) {

            return null;

        }


        //If some of the method returns the original object

        //we swap the returned object by our proxy

        if (invoke == instance) {

            return proxy;

        }


        //TODO: check if you want to swap in place

        //other interfaces

        if (interfaces.contains(method.getReturnType())) {

            return IPageProxy.proxy((IPage)invoke);

        }

        return invoke;

    }

}


class MyIEventDesignDialog implements IEventDesignDialog {

    @Override

    public IEventDesignDialog getShow() {

        return null;

    }


    @Override

    public IEventDesignDialog getEventType() {

        return null;

    }


    @Override

    public IEventDesignDialog getDateAndTimeDisplayFormat() {

        return null;

    }

}

输出:


*   Dynamic proxy invoke method executed for getEventType

get event type method invoked successfully

*   Dynamic proxy invoke method executed for getShow

get show method invoked successfully

*   Dynamic proxy invoke method executed for getDateAndTimeDisplayFormat

get date and time display format method invoked successfully

*   Dynamic proxy invoke method executed for getShow

您可以从 Mockito 的工作方式中获得灵感。请查看此页面:https ://static.javadoc.io/org.mockito/mockito-core/2.27.0/org/mockito/Mockito.html#spy-T-


我知道它是用于测试的,但您仍然可以从中获得想法。所以你可以在一个类和一个对象上应用 spy() 来监视它。


查看完整回答
反对 回复 2022-11-02
?
慕盖茨4494581

TA贡献1850条经验 获得超11个赞

我已经通过使用返回代理实例的默认方法创建一个接口来解决这个问题,然后在执行调用的方法功能后返回它:


更新代码:


public interface IPage {

    default <T extends IPage> T getProxyInstance() {

        try {

            return (T) IPageProxy.getInstance(this.getClass());

        } catch (InstantiationException | IllegalAccessException e) {

            e.printStackTrace();

        }

        return null;

    }

}

我的页面界面:


@Page(path = "MyPath")

public interface IEventDesignDialog extends IPage{

    @Entity(visibileName = "Show")

    public IEventDesignDialog getShow();


    @Entity(visibileName = "Date And Time display format")

    public IEventDesignDialog getDateAndTimeDisplayFormat();


    @Entity(visibileName = "Event Type")

    public IEventDesignDialog getEventType();    

}

我的页面类:


@Page(path = "MyPath")

public class EventDesignDialog implements IEventDesignDialog{

        @Entity(visibileName = "Show")

        public IEventDesignDialog getShow() {

            System.out.println("get show method invokde successfully");

            return getProxyInstance();

        }


        @Entity(visibileName = "Date And Time display format")

        public IEventDesignDialog getDateAndTimeDisplayFormat() {

            System.out.println("get date and time display format method invokde successfully");

            return getProxyInstance();

        }


        @Entity(visibileName = "Event Type")

        public IEventDesignDialog getEventType() {

            System.out.println("get event type method invokde successfully");

            return getProxyInstance();

        }

}

主类:


public class Main {


    public static void main(String[] args) {

        try {

            IEventDesignDialog a  = ((IEventDesignDialog)getInstance(EventDesignDialog.class)).getEventType().getShow();


            ((IShowDesignDialog)getInstance(ShowDesignDialog.class)).getShowName().getShowType();

        } catch (InstantiationException | IllegalAccessException e) {

            e.printStackTrace();

        }

    }



    @SuppressWarnings("unchecked")

    public static <T extends IPage> T getInstance(final Class<? extends IPage> type) throws InstantiationException, IllegalAccessException {

        return (T) IPageProxy.getInstance(type);

    }


}

IProxy 页面保持不变,无需更改。


查看完整回答
反对 回复 2022-11-02
  • 2 回答
  • 0 关注
  • 148 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号