2013-07-30 1 views
1

Недавно я работал с объектами прокси, я сделал свой трудный вопрос ... я хотел бы поделиться им и получить ваше мнение ... возможно, решение ... если вопрос окажется действительный.Методы проксированных объектов

Используя динамический прокси, идея заключается в том, чтобы делегировать работу в другую class, реализующий InvocationHandlerinterface и перезапись метода Invoke мы можем перехватывать любой метод вызывается на целевом объекте, предоставляя также возможность добавить поведение, а затем делегирование к целевому объекту (возможно, реальному или другому прокси) с использованием отражения. У вас должен быть interface, который обеспечивает concreteclass, чьи объекты мы предпочитаем проксимизировать. Поэтому мы работаем с интерфейсом.

Вопрос, я думаю, приходит, потому что с объектами proxies перехвачен только первый вызываемый метод ... это означает: если внутри метода объекта concrete (объект, класс которого конкретный, а не интерфейс), есть вызовы другим методам экземпляра, эти методы будут непосредственно вызываться объектом concrete, а не через прокси (там, прежде чем не передумать обработчик вызова снова). Я знаю, что класс «Динамический прокси» считается подклассом interface, но не класса concrete .. поэтому внутри класса concrete ключевое слово «это» не может ссылаться на прокси-объект, поскольку прокси-сервер класс объекта не является подтипом concrete .., на самом деле это «родной брат» concrete, потому что concrete и класс «Динамический прокси» являются подтипами interface.

Пожалуйста, взгляните на следующий сценарий и введите следующий код, в котором я нашел довольно проблемную ситуацию.

public class Example 
{ 

    static interface OutputerInterface 
    { 
     String getText(); 

     void out(); 

     void setText(String data); 

    } 

    static class Outputer implements OutputerInterface { 

     private String txt; 

     public Outputer() 
     { 
      this.txt = null; 
     } 

     @Override 
     public String getText() 
     { 
      return txt; 
     } 

     @Override 
     public void setText(String data) 
     { 
      this.txt = data; 
     } 

     @Override 
     public void out() { 
      String text = this.getText(); 
      System.out.println (text); 
     } 
    } 

    static class OutputerInvocationHandler implements InvocationHandler { 
     private OutputerInterface outputer; 

     public OutputerInvocationHandler(OutputerInterface concreteEntity) 
     { 
      this.outputer = concreteEntity; 
     } 

     @Override 
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
     { 
      String methodName = method.getName(); 
      System.out.println("Intercepted " + methodName); 
      if (methodName.equals("getText")) 
      { 
       if (this.outputer.getText() == null) { // only if not setted 
        this.outputer.setText("Hi, i am outputer"); 
       } 
      } 

      return method.invoke(outputer, args); 
     } 
    } 

    static OutputerInterface proxify (OutputerInterface entity) { 
     return (OutputerInterface) Proxy.newProxyInstance(
       Outputer.class.getClassLoader(), 
       Outputer.class.getInterfaces(), 
       new OutputerInvocationHandler(entity)); 
    } 


    public static void main(String[] args) 
    { 
     OutputerInterface outputer; 

     outputer = proxify (new Outputer()); 
     String text = outputer.getText(); 
     System.out.println (text); // this works! 

     outputer = proxify (new Outputer()); 
     outputer.out(); // this doesn´t works 
    } 
} 

Есть Есть ли способ, чтобы убедиться, что GetText() перехватывается, где он вызывается непосредственно из прокси или нет. Спасибо! Приветствую! Виктор.

ответ

1

Это ограничение встроенных динамических прокси Явы: можно реализовать только несколько интерфейсов, но никогда не расширяйте класс.

В вашем случае, предположим, что вы пытаетесь это сделать, это расширить Outputer и нет, вы не можете сделать это с помощью динамических прокси-серверов. Вместо этого вы должны попробовать библиотеку генерации кода времени выполнения, например CGLib.

+0

Чертов мартин. Я вижу, что это ограничение.Я не знаю немного CGLib (только эта реализация спящего и весеннего библиотек использует его, чтобы сделать свою магию за шторами). – Victor

+0

@Victor Это не относится к динамическим прокси, но именно так работают объектно-ориентированные языки: если вы переносите объект A с объектом B, объект A 'this' всегда будет связываться с A и никогда не B. Вам просто нужно, чтобы B * продолжал * A. –

+0

Да, но сценарий, который изначально заставляет меня добраться до этой точки является более сложным, чтобы объяснить здесь, и наследование не представляется возможным ... поэтому мне удалось решить проблему по-другому. Но это совершенно другая тема, мой друг. – Victor

1

Вам необходимо предоставить конкретный класс со ссылкой на InvocationHandler, который ведет его, и использовать эту ссылку вместо «this» (uimplicit или explicit) в местах appopriate.

Или вы могли бы иметь конкретный класс реализоватьInvocationHandler, хотя это трудно понять точку ;-)

+0

Я вижу ... но это означает, что конкретный класс знает о том, что он проксирован другим ... заставляя установить новую зависимость (циклическую) ... последнее средство решения i. – Victor

+0

Возможно, что-то, что вы ищете, - это действительно производный класс, вообще не связанный с динамическими прокси-серверами? – EJP

+0

О, извините @EJP, я просто вижу ваш комментарий ... как я говорю Мартину, поскольку моя конкретная проблема не может использовать наследование. Но я тоже об этом подумал. – Victor

Смежные вопросы