Java 7 - 自定义方法修饰,没有默认委托all,其他很多方法

时间:2016-06-27 13:04:18

标签: java java-7 decorator proxy-classes invocationhandler

我想decorate接口PreparedStatement,以便自定义关闭它(只是一个示例)。

这意味着我想装饰PreparedStatement的现有实例,因此,在调用close()时调用其他代码。

为此,我需要默认实现PreparedStatement装饰器的所有数十方法,只是为了委托对内部对象的调用,比如done here。垮台的原因是它只是很多工作和代码而没什么附加价值。

另一个选择是尝试使用Java的Proxy and InvocationHandler,以便提供一个默认实现,为单个方法中的所有方法执行委托。如果存在自定义方法,则InvocationHandler会将调用定向到该方法。请参见示例here。 此解决方案的问题是自定义方法无法标记为 @Override ,并且无法检查其签名的正确性,因为它需要抽象PreparedStatement,代理将无法实例化。

那么,这可以吗?怎么样?

*必须能够使用Java 7 max实现,但可以随意提供Java 8答案。

3 个答案:

答案 0 :(得分:0)

据我所知,您希望提供给PreparedStatement接口的具体实现。我能想到的唯一方法是创建实现接口的抽象类。通过这样做,您不需要从界面实现所有方法,并且您将获得所需的实现。

我会尝试这样的事情:

public abstract class MyPreparedStatement implements PreparedStatement {

@Override
public void close() throws SQLException {
    System.out.println("Closing");
}

public static void main(String[] args) throws SQLException {
    Connection con = null;
    MyPreparedStatement statement = (MyPreparedStatement) con.prepareStatement("sql");
}
}

答案 1 :(得分:0)

您能更清楚地解释Proxy解决方案缺乏的内容吗?考虑这样的事情,它依赖于AOP特色的钩子':

final PreparedStatement original = ...;
final InvocationHandler delegator = new InvocationHandler() {

  void onClose() {
    /* do stuff */
  }

  Object invoke(final Object proxy, final Method method, final Object[] args) {
    if (method.getName().equals("close")) {
      onClose();
    }

    return method.invoke(original, args);
  }
};
final PreparedStatement wrapped = (PreparedStatement) Proxy.newProxyInstance(this.getClass().getClassLoader(),
    new Class<?>[] { PreparedStatement.class }, delegator);

答案 2 :(得分:-1)

如果您无法访问这些方法以便与它们进行常规继承,那么您可以使用面向方面编程,利用AspectJ或Spring Framework完成您尝试执行的操作方面功能,为您所需的方法提供建议。

一个简单的方面基本上归结为:

@Aspect
public class MyAspect {

    @Pointcut("execution(* *(..))") //Replace expression with target method; this example 
    //will hit literally every method ever.
    public void targetmethod() {}; //Intentionally blank.
    //AspectJ uses byte code manipulation (or "black magic voodoo", if you 
    // will) to make this method a surrogate for any real one that matches the pointcut

    @Before("targetmethod()") //Or @After, or @Around, etc...
    public void doStuff() throws Throwable {
        //Put your code here
    }
}

将各个方面放在一起后,将它们添加到aop.xml中并编织方面(可以在编译时使用适当的构建管理器配置执行此操作,也可以在运行时通过使用java -javaagent:/path/to/aspectjweaver.jar运行aspectjweaver)来执行此操作。

这确实附带了一个免责声明:对java。*类这样的事情可以让你以新的和有趣的方式分解你所引入的所有副作用(事实上,AspectJWeaver拒绝编织默认情况下,java。*类,但您可以覆盖该设置)。要非常清楚你在做什么,并明智地使用你的方面和方法。