2010-05-03 12 views
7

Java generuje klasę proxy dla danego interfejsu i udostępnia instancję klasy proxy. Ale kiedy wpisujemy obiekt proxy do naszego konkretnego obiektu, jak java obsługuje to wewnętrznie? Czy jest to traktowane jako scenariusz specjalny?W języku Java, w jaki sposób instancja i typ rzutowania (np. (ClassName)) działa na obiekcie proxy?

Na przykład mam klasy OriginalClass i realizuje OriginalInterface, podczas tworzenia obiektu proxy przepuszczając OriginalInterface interfejsu Java utworzony klasy proxy ProxyClass stosując metody opisane w przewidzianym złącza i zapewnia przedmiot tej klasy (tj. ProxyClass). Jeśli moje rozumienie jest poprawne wtedy można proszę odpowiedzieć na następujące pytania

  1. Po wpisaniu rzutować obiektu ProxyClass do mojej klasy OriginalClass to działa, ale jak Java jest umożliwienie tym? To samo w przypadku instace?
  2. Zgodnie z moją wiedzą Java tworzy klasę proxy tylko za pomocą metod, ale co się stanie, gdy spróbuję uzyskać dostęp do atrybutów tego obiektu?
  3. Tylko metody interfejsu są wdrażane w proxy, ale co się dzieje, gdy próbuję uzyskać dostęp do metody, która nie jest w interfejsie i jest wymieniona tylko w klasie?

Dzięki Student

+1

Czy jesteś pewien, że odsyłasz swoje proxy do dzieł OriginalClass? W moim rozumieniu, jeśli utworzyłeś proxy dla OriginalInterface, nie powinieneś być w stanie rzucić na OriginalClass –

Odpowiedz

11

Java nie pozwala odlewania od pełnomocnika do konkretnej klasy. Proxy JDK (java.lang.reflect.Proxy) są tylko serwerami proxy interfejsu. Wynikowym proxy jest typ ProxyX (X jest liczbą), a jeśli spróbujesz rzucić go do dowolnej klasy, otrzymasz ClassCastException

. Dlatego Twoje drugie i trzecie pytanie nie są istotne - serwer proxy nie jest wspierany przez konkretna klasa. Aby to osiągnąć, możesz użyć innych mechanizmów proxy - CGLIB lub javassist. Używają podklasy ynamic, więc wszystkie pola i metody są dostępne dla podklasy (proxy).

+0

Dziękuję bardzo za szybką odpowiedź. Java nie pozwala rzutować na konkretną klasę. – learner

7

Z Javadocs API dla java.lang.reflect.InvocationHandler:

InvocationHandler jest realizowany przez interfejs obsługi wywołania instancji proxy.

Dynamiczny serwer proxy implementuje interfejs, ale korzysta z procedury obsługi (OriginalClass) w celu zapewnienia podstawowych implementacji metod.

Aby odpowiedzieć na Twoje pytania:

  1. Kompilator pozwoli Ci rzucić tak długo jak nie ma wystarczających informacji, aby mieć pewność, że obsada nie może się udać. Zachowanie w czasie wykonywania testów rzutowania i instancji dla dynamicznych serwerów proxy opisano w javadoc dla java.lang.reflect.Proxy. Testy rzutowania i instancji będą skuteczne, jeśli są używane z interfejsami, ale nie, jeśli są używane z klasami.
  2. Nie można uzyskać dostępu do żadnych atrybutów za pomocą dynamicznego proxy, ponieważ implementuje interfejs, nie rozszerza klasy obsługi.
  3. Nie można uzyskać dostępu do metod, które nie zostały zadeklarowane w interfejsie za pomocą dynamicznego proxy, ponieważ implementuje interfejs, nie rozszerza klasy obsługi.

Wewnątrz implementacji dynamicznego proxy (np. W implementacji wywołania (...)) można uzyskać dostęp do członków obsługi za pomocą refleksji.

Oto niektóre kodu testu, który kiedyś sprawdzić moją odpowiedź:

// package ...; 

import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 

import junit.framework.Assert; 

import org.junit.Test; 

public class TestDynamicProxy 
{ 
    @Test 
    public void testCast() throws Exception { 
     Foo foo = (Foo) TestProxy.newInstance(new FooImpl()); 
     foo.bar(null); 

     System.out.println("Class: " + foo.getClass()); 
     System.out.println("Interfaces: " + foo.getClass().getInterfaces()); 

     Assert.assertNotNull(foo); 
     Assert.assertTrue(foo instanceof Foo); 
     Assert.assertFalse(foo instanceof FooImpl); 
    } 
} 

interface Foo 
{ 
    Object bar(Object obj) throws Exception; 
} 

class FooImpl implements Foo 
{ 
    public Object bar(Object obj) throws Exception { 
     return null; 
    } 
} 

class TestProxy implements java.lang.reflect.InvocationHandler 
{ 
    private final Object obj; 

    public static Object newInstance(Object obj) { 
     return java.lang.reflect.Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new TestProxy(obj)); 
    } 

    private TestProxy(Object obj) { 
     this.obj = obj; 
    } 

    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable { 
     Object result; 

     try { 
      result = m.invoke(obj, args); 
     } 
     catch (InvocationTargetException e) { 
      throw e.getTargetException(); 
     } 
     catch (Exception e) { 
      throw new RuntimeException("unexpected invocation exception: " + e.getMessage()); 
     } 

     return result; 
    } 
} 

Ten article ma wiele przydatnych informacji i przykładowy kod.

+0

Dziękuję bardzo. Twoje informacje są tak pomocne. – learner

Powiązane problemy