【发布时间】:2013-07-13 21:50:56
【问题描述】:
我有一个由带有 getter/setter 方法的接口组成的对象模型。这些对象的实现是使用动态代理创建的,其中隐含字段的值(使用 JavaBean 命名约定)存储在 Map 中。
我想为这些接口添加方法以提供业务逻辑(你知道,就像一个真实的对象模型,而不仅仅是 POJO 的集合)。
我的第一个想法是创建实现每个接口但只提供业务方法的实现的抽象类。然后我会将这些实现与 InvocationHandler 中的 Map 一起使用,以提供接口的完整实现。
类似:
interface ModelObject extends BaseModel {
void setFoo(String foo);
String getFoo();
void doSomething();
}
public abstract class ModelObjectImpl implements ModelObject {
@Override
public void doSomething()
{
// Do something
}
}
public class ModelObjectInvocationHander implements InvocationHandler {
Map<String, Object> fieldValues; // holds values for implied fields for getter setter
ModelObject modelObject; // holds reference to object implementing business methods
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Get implied field name for method name by removing "get"/"set" and lower casing next letter
String fieldName = getBeanNameForMethod(method.getName());
if (fieldValues.containsKey(fieldName)) {
return fieldValues.get(fieldName);
}
// Not a getter/setter so must be a business method. Delegate to implementation class
return method.invoke(modelObject, args);
}
}
除了我不能创建抽象类的实例之外,这样的东西(但显然更复杂)会起作用。我可以使 BusinessObjectImpl 非抽象并添加永远不会调用的 getter/setter 方法的无操作实现,但这只会使代码变得丑陋并导致维护问题。我也可以让 BusinessObjectImpl 实际上不实现 BusinessObject 接口,但是这会破坏实现和接口之间的良好绑定,从而在接口和“实现”不同步时导致错误。
有没有什么鬼鬼祟祟的 Java 反射技巧可以用来调用这些业务方法?
更新: 结合现有的 Java 动态代理框架和Javassist 为抽象实现类创建代理。这允许在根据需要添加业务方法之前对现有模型接口完全没有任何更改。现在已经具备向对象添加行为的能力。现在由开发人员开始编写真正的面向对象代码。
public class ModelObjectInvocationHandler implements InvocationHandler
{
public ModelObjectInvocationHandler(Class<ModelImplementation<? extends BaseModel>> implementationClass)
{
if (implementationClass != null)
{
ProxyFactory factory = new ProxyFactory();
factory.setSuperclass(implementationClass);
try
{
modelObject = (ModelObject) factory.create(new Class<?>[0], new Object[0]);
}
catch (Exception e)
{
// Exception handling
}
}
}
Map<String, Object> fieldValues; // holds values for implied fields for getter setter
ModelObject modelObject; // holds reference to object implementing business methods
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
// Get implied field name for method name by removing "get"/"set" and lower casing next letter
String fieldName = getBeanNameForMethod(method.getName());
if (fieldValues.containsKey(fieldName))
{
return fieldValues.get(fieldName);
}
// Not a getter/setter so must be a business method. Delegate to implementation class
if (modelObject != null)
{
return method.invoke(modelObject, args);
}
return null;
}
}
在运行时,我会扫描实现类并创建一个Map<Class<? extends BaseModel>, Class<ModelImplementation>>。在为接口创建动态代理时,我在映射中找到它的实现类,并将其传递给InvocationHandler。任何与 bean 名称不匹配的方法都将委托给实现类的代理。当然,这比这要复杂一些,因为我必须考虑模型接口中的类层次结构和多重继承,但理论是合理的。
【问题讨论】:
标签: java reflection dynamic-proxy