我正在研究一个老化的Java“Swing”应用程序,不幸的是,它使用非线程安全的数据模型。随着具有多线程和多核PC的客户端数量的增加,由于非同步访问数据而导致的伪随机错误数量也在增加。我们有一个巨大的代码库,类似于6000个Java文件,其中大部分都非常庞大和复杂。
我想创建一个全局静态ReentrantReadWriteLock来控制对模型的访问。我的计划是创建一个虚拟的ReadWriteLock实现,它总是成功但不做任何事情,并在生产系统上使用它,同时在测试系统上使用ReentrantReadWriteLock,以便转换可以是渐进的。
我需要的是一种“拦截”测试系统中对模型的所有访问的方法,如果访问不在适当的锁定/解锁块的范围内,则记录错误。 ReentrantReadWriteLock可以告诉您是否拥有写锁定。我假设我可以通过使用ThreadLocal或其他东西来跟踪读锁定状态。
现在出现了一个真正的问题:在Java中,我怎么能编写代码,在运行时拦截对定义良好的类集中的任何公共方法的任何访问,并检查访问是否在锁定/解锁内阻止,通过查询全局锁?可以用AspectJ完成吗?还是其他什么?怎么样?
答案 0 :(得分:1)
您可能会发现java proxies有用
您不能将invokation处理程序添加到现有对象,但您可以在代理中“包装”您的类的实例。创建的代理对象仍然是MyClass
类型。
答案 1 :(得分:1)
我认为它可以用AspectJ完成但是我没有用它来知道如何。
相反,我要做的是使用要捕获的类的修改副本并将它们添加到bootclasspath。例如更改FileInputStream和FileOutputStream的副本。
对于测试系统,这项工作非常简单。我不会鼓励你在制作中这样做。
答案 2 :(得分:1)
我不知道这对您的情况有多适用,但拦截方法调用的最佳方法是使用动态代理。为此,您必须为您的类创建接口,无论如何您都可以这样做。
以下是动态代理如何工作的示例:
interface Foo {
void setBar( String bar );
String getBar();
}
class FooImpl implements Foo {
private String bar;
// getter and setter
}
这是您的正常代码。现在你可以做的是代替new FooImpl()
你可以使用代理。对于代理,您首先需要[InvocationHandler][1]
。
class LockHandler implements InvocationHandler {
private FooImpl originalOb;
public LockHandler( FooImpl originalOb ) {
this.originalOb = originalOb;
}
@Override
public Object invoke( Object proxy, Method method, Object [] args ) {
try {
if( method.getName().startsWith( "set" ) {
// do locking stuff
}
return method.invoke( originalOb, args ); //invoke underlying method
} finally {
if( method.getName().startsWith( "set" ) {
// do post-call locking stuff
}
}
}
}
然后你最终创建了你的Proxy
对象:
Foo foo = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class[] { Foo.class },
new LockHandler( new FooImpl() ) );
现在,对foo
对象的每次调用都将被引导到您的调用处理程序中。当然,您不必为每个对象创建一个新的调用处理程序实例,您甚至不需要为每个接口单独使用一个,originalOb
可以(并且在现实生活中)应该声明为{{1 }类型。
另一种选择是使用AspectJ这样的方面实现,它可能更易于使用,但引入它可能为时已晚,具体取决于您在软件开发方面的进展。