2010-04-05 76 views
11

我看到這個問題應用服務器如何注入私人領域?

Inject into private, package or public field or provide a setter?

有關如何手動注入註釋的私人領域(的方式是將setter方法 或通過構造函數)

但是,問題是怎麼做的應用服務器(如glassfish,axis2,jboss,...) 能夠注入最終的私有字段(不需要向用戶類添加setter或構造函數 )?

引述引述問題:

public SomeClass { 
    @Inject 
    private SomeResource resource; 
} 

他們是否使用定製的JVM(未標一),允許訪問私有字段?

謝謝

+0

這是私人的,但不是最終的。你在代碼塊中錯過了* final *嗎?因爲我認爲不可能注入私人最終成員。 (糾正我,如果我錯了。) – whiskeysierra 2010-04-05 22:02:01

+0

@威利:你說得對。在下面的代碼示例中,我放了final,但即使doInjection()方法沒有提出錯誤,值也沒有更改。所以我刪除了最後的。 – cibercitizen1 2010-04-06 07:41:33

回答

16

這是一個簡單的反思「詭計」。它依賴於Field.setAccessible()方法迫使構件可訪問編程:

設置accessible標誌此 對象指示的布爾值。 值爲true表示在使用 時,反射對象應禁止Java 語言訪問檢查。值爲false表示 反映的對象應強制執行 Java語言訪問檢查。

Reflection API用於獲取該字段的句柄,調用setAccessible(),然後可以通過注入框架設置它。

查看示例here

沒有魔力,沒有自定義虛擬機。

+0

@skaffman非常好! – cibercitizen1 2010-04-05 15:45:19

+0

謝謝,但我不能讚揚它:) – skaffman 2010-04-05 15:46:02

6

在skaffman的幫助下,我編寫了一個簡單的例子,說明如何在沒有setter的情況下進行注入。 也許它可以幫助(這對我做了)

//...................................................... 
import java.lang.annotation.*; 
import java.lang.reflect.*; 

//...................................................... 
@Target(value = {ElementType.FIELD}) 
@Retention(RetentionPolicy.RUNTIME) 
@interface Inject { 
} 

//...................................................... 
class MyClass { 

    @Inject 
    private int theValue = 0; 

    public int getTheValue() { 
     return theValue; 
    } 
} // class 

//...................................................... 
public class Example { 

    //...................................................... 
    private static void doTheInjection(MyClass u, int value) throws IllegalAccessException { 

     Field[] camps = u.getClass().getDeclaredFields(); 

     System.out.println("------- fields : --------"); 
     for (Field f : camps) { 
      System.out.println(" -> " + f.toString()); 
      Annotation an = f.getAnnotation(Inject.class); 
      if (an != null) { 
       System.out.println("  found annotation: " + an.toString()); 
       System.out.println("  injecting !"); 
       f.setAccessible(true); 
       f.set(u, value); 
       f.setAccessible(false); 
      } 
     } 

    } //() 

    //...................................................... 
    public static void main(String[] args) throws Exception { 

     MyClass u = new MyClass(); 

     doTheInjection(u, 23); 

     System.out.println(u.getTheValue()); 

    } // main() 
} // class 

運行輸出:

------- fields : -------- 
-> private int MyClass.theValue 
     found annotation: @Inject() 
     injecting ! 
23 
3

另外值得一提的是,一些框架通過自定義類加載器使用字節碼工程,以達到相同的結果,而沒有成本的反射(有時反射可能相當昂貴)