2014-04-10 16 views
10

Tôi đang sử dụng CDI làm khuôn khổ tiêm, nhưng tôi đã tìm thấy một số hạn chế trong việc sử dụng nó, và đây là một trong số chúng. Tôi đang cố gắng khởi tạo việc tạo một cá thể bean với giá trị thời gian chạy là. Ví dụ:Vượt qua tham số để thể hiện của @Inject Bean

@RequestScoped 
public class MyNumber { 
    int number; 

    public MyNumber(int number) { 
     this.number = number; 
    } 

    public String toString() { 
     return "Your number is: " + number; 
    } 
} 

public class UseNumber { 
    @Inject 
    Instance<MyNumber> number; 

    public void doStuff() { 
     int a = 8; 
     MyNumber mN = number.select(a).get(); // ?? - Obviously this does not work. 

     System.out.print(mN); // Should print: "Your number is: 8" 
    } 
} 

Xin lưu ý rằng "a" là hằng số trong ví dụ, nhưng thực tế nó là một biến; Tôi làm rõ điều này để bạn không đăng câu trả lời với số @Producer để tiêm giá trị sau đó vào hàm tạo của MyNumber.

Bây giờ, ai cũng có ý tưởng về cách tôi có thể làm điều đó?

Trả lời

4

Theo đặc điểm kỹ thuật, không có cách nào để có một bean với một hàm tạo không đơn giản, "không tiêm" ( 3.1. Managed beans, 3.9. Bean constructors). Vì vậy, các cách để thiết lập các tham số là phải có setMethod() cho chúng, làm cho chúng thành các trường @Inject trong bean hoặc chú thích hàm tạo với chú thích @Inject và làm cho các tham số của hàm tạo được tiêm vào. ( 5.5.1. Injection using the bean constructor)

Tôi hy vọng, tôi đã trả lời câu hỏi.

10

Tôi không chắc chắn những gì bạn đang cố gắng làm, nhưng từ những gì tôi hiểu bạn muốn khởi tạo bean của bạn với dữ liệu trong chú thích điểm tiêm hoặc thời gian chạy qua tra cứu có lập trình. Bạn có thể thực hiện việc này bằng cách sử dụng dữ liệu meta InjectionPoint trong bean của bạn (hạn chế duy nhất là đặt bean của bạn trong phạm vi phụ thuộc)

Bạn có thể làm điều gì đó như thế này.

Trước tiên hãy tạo vòng loại có giá trị không ràng buộc.

@Qualifier 
@Target({TYPE, METHOD, PARAMETER, FIELD}) 
@Retention(RUNTIME) 
@Documented 
public @interface Initialized { 

    @Nonbinding int value() default 0; // int value will be store here 
} 

Bạn phải thêm vòng loại này vào hạt của mình và phân tích InjectionPoint khi tạo.

@Initialized 
public class MyNumber { 
    int number; 

    private int extractValue(InjectionPoint ip) { 
    for (Annotation annotation : ip.getQualifiers()) { 
     if (annotation.annotationType().equals(Initialized.class)) 
      return ((Initialized) annotation).value(); 
    } 
    throw new IllegalStateException("No @Initialized on InjectionPoint"); 
    } 

    @Inject 
    public MyNumber(InjectionPoint ip) { 
     this.number = extractValue(ip); 
    } 

    public String toString() { 
     return "Your number is: " + number; 
    } 
} 

Bây giờ bạn có thể tiêm một số khởi tạo như thế này:

@Inject 
@Initialized(8) 
MyNumber number; 

Nếu bạn muốn quyết định giá trị khởi tạo trong thời gian chạy, bạn sẽ phải sử dụng tra cứu theo chương trình:

Đầu tiên tạo chữ chú thích cho `@ Initialized``

public class InitializedLiteral extends AnnotationLiteral<Initialized> implements Initialized { 

    private int value; 

    public InitializedLiteral(int value) { 
     this.value = value; 
    } 

    @Override 
    public int value() { 
     return value; 
    } 
} 

Sau đó, bạn có thể sử dụng Instance để tạo hạt của bạn.

public class ConsumingBean { 

    @Inject 
    @Any 
    Instance<MyNumber> myNumberInstance; 

    public MyNumber getMyNumberBeanFor(int value) { 
    return myNumberInstance.select(new InitializedLiteral(value)).get(); 
    } 
    ... 
} 

Ghi làm việc này chỉ khi MyNumber là trong phạm vi phụ thuộc có ý nghĩa bởi vì đó là cách duy nhất để thay đổi giá trị khởi tạo ở từng tiêm.

+0

rất tốt, +1, phiếu bầu của tôi !!! :) – Delfino

+0

@Antoine, ví dụ bạn cung cấp đang hoạt động tốt, nhưng nếu có thể linh hoạt như bỏ qua sử dụng chú thích đã khởi tạo trong khi tiêm lớp MyNumber từ một số lớp nếu không cần truyền tham số? –

Các vấn đề liên quan