我有一种情况,我想拦截/覆盖外部(我没有访问它们)对象的方法.我的情况的一个例子:
我有一个外部对象:
public class ExternalObject {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Run Code Online (Sandbox Code Playgroud)
一个外部阶级女巫使用它:
public class ExternalClass {
public static void main(String[] args) {
ExternalObject o = new ExternalObject();
o.setName("Tom");
MyClass.doSomething(o);
o.setName("Jerry");
System.out.print(o.getName());
}
}
Run Code Online (Sandbox Code Playgroud)
然后有MyClass女巫有一个机会来访问外部对象:
public class MyClass {
public static void doSomething(ExternalObject o){
}
}
Run Code Online (Sandbox Code Playgroud)
是否可以覆盖或修改MyClass中的setName方法?我需要的是setName方法检查名称是否是"jerry"然后将其更改回"tom",如果没有,则执行原始方法的操作.
像这样的东西:
public void mySetName(String name){
if(name.equals("Jerry"){
name = "Tom";
}
doWhatOriginalMethodDoes();
}
Run Code Online (Sandbox Code Playgroud)
因此,如果有人像现在一样运行外部类,那么Tom将被打印两次.
顺便说一句,外部(原始)对象和方法非常复杂.我已经四处搜索,这应该可以与reflect.Proxy做,但我不能让它工作.
谢谢你的帮助!:)
最简单的方法是使用继承:
public class MySubClass extends ExternalObject {
private ExternalObject obj;
public MySubClass(ExternalObject obj) {
this.obj = obj;
}
@Override
public void setName(String name){
if(name.equals("Jerry") {
super.setName("Tom");
} else {
super.setName(name);
}
}
// override all public method to call super method
@Override
public AClass otherMethod1(BClass arg){
return super.otherMethod1(arg);
}
@Override
public CClass otherMethod2(DClass arg){
return super.otherMethod2(arg);
}
}
Run Code Online (Sandbox Code Playgroud)
由于MySubClass是一个ExternalObject,你可以调用:
MySubClass subObject = new MySubClass(o);
MyClass.doSomething(subObject);
Run Code Online (Sandbox Code Playgroud)
或者,如果您的类实现了一个接口,您可以使用代理:
首先,定义一个InvocationHandler
public Class ExternalObjectInterfaceInvocationHandler implements java.lang.reflect.InvocationHandler {
// keep a reference to the wrapped object
private ExternalObjectInterface obj;
public ExternalObjectInterfaceInvocationHandler(ExternalObjectInterface obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {
try {
if (m.getName().equals("setName")) {
// do something
}
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw e;
}
// return something
}
}
Run Code Online (Sandbox Code Playgroud)
然后使用代理包装您的对象:
ExternalObjectInterface obj = ...
//wrap the obj with a proxy
ExternalObjectInterface wrappedInstance = (ExternalObjectInterface) Proxy.newProxyInstance(
ExternalObjectInterface.class.getClassLoader(),
new Class[] {ExternalObjectInterface.class},
new ExternalObjectInterfaceHandler( obj )
);
Run Code Online (Sandbox Code Playgroud)
然后打电话:
MyClass.doSomething(wrappedInstance);
Run Code Online (Sandbox Code Playgroud)
如果您的对象没有实现接口,第三种解决方案是使用CGLib:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
Run Code Online (Sandbox Code Playgroud)
要包装您的对象,您可以使用以下内容:
public static <S,W> W createWrapper(final S source, final Class<W> wrapperClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(wrapperClass);
enhancer.setInterfaces(wrapperClass.getInterfaces());
enhancer.setCallback(new MethodInterceptor() {
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if ("setName".equals(method.getName())) {
//do something
return null;
}
if (Arrays.asList(wrapperClass.getDeclaredMethods()).contains(method)) {
return methodProxy.invokeSuper(proxy, args);
}
return methodProxy.invoke(source, args);
}
});
return (W) enhancer.create();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1603 次 |
| 最近记录: |