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() 来监视它。

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 页面保持不变,无需更改。
添加回答
举报