2014-04-10 16 views
8

Tôi đang sử dụng mã như dưới đây:CDI Sự phụ thuộc không rõ ràng với @Sản phẩm - tại sao?

public Configuration { 

    private boolean isBatmanCar = someMethod(...); 

    @Produces 
    public Car getCar(@New Car car) { 
     if(isBatmanCar) { 
      car.setName("BatmanCar"); 
     } 
     return car; 
    } 
} 

public Car { 
    private String name = "NormalCar"; 

    public void setName(String name) { 
     this.name = name; 
    } 
} 

public Demo { 
    @Inject 
    Car car; 

    // rest of code 
} 

Khi tôi triển khai một ứng dụng để Glassfish (Java EE 6 btw) tôi nhận được

AmbiguousResolutionException: WELD-001318 Cannot resolve an ambiguous dependency between (...) Car with qualifiers [@Any @Default] (...) Producer Method [Car] with qualifiers [@Any @Default]

Tôi biết rằng khi tôi thêm @Alternative đến lớp Car nó sẽ hoạt động, nhưng tôi tự hỏi liệu đây có phải là cách thích hợp để làm điều đó không, và tại sao tôi phải làm điều đó?

Bạn có thể cho tôi biết cách sử dụng đúng của @Sản phẩm trong trường hợp này không?

Tôi đang sử dụng Java EE 6, CDI 1.0, EJB 3.1, Glassfish 3.2

Trả lời

12

Lỗi xuất phát từ thực tế là bạn có 2 đậu kiểu Car, một là lớp, còn lại là nhà sản xuất. Bạn có 2 giải pháp rõ ràng để giải quyết sự mơ hồ:

Đầu tiên, bạn đặt logic đằng sau isBatmanCar trường trong lớp gốc (trong phương thức khởi tạo hoặc ví dụ @PostConstruct) và xóa nhà sản xuất của bạn. Điều đó chỉ còn lại một hạt Car.

Hoặc nếu bạn thực sự muốn có 2 đậu hay không có thể tránh được nó, bạn nên tạo một vòng cho đậu sản xuất của bạn:

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

và sử dụng nó trên nhà sản xuất,

@Produces 
@BatmanChecked 
public Car getCar(Car car) {...} 

để có thể tiêm loại xe

@Inject 
Car stdCar; 

@Inject 
@BatmanChecked 
Car batCheckedCar; 

Vòng loại là tùy chọn tự nhiên để giải quyết vấn đề tiêm mơ hồ. Sử dụng @Alternative cũng hoạt động nhưng nó là một thủ thuật ở đây hơn là một thực hành tốt.

Nhận xét cuối cùng: @New là không cần thiết ở đây, vì hạt Car của bạn không có phạm vi (như vậy là @Dependent phạm vi). @New chỉ hữu ích khi nhà sản xuất tiêm một hạt với phạm vi không phải là @Dependent. Điều đó nói rằng, mã này không hữu ích nếu lớp học Car của bạn nằm trong phạm vi @Dependent.

+0

Thực tiễn tốt để sử dụng @Alternative là gì? – dmydlarz

+0

@Alternative cho phép bạn đề xuất phiên bản khác nhau cho cùng một loại bean (loại) và kích hoạt nó theo cấu hình trong tệp cấu hình. Nó có thể được sử dụng để có một ben khác trong dev/test và trong sản xuất ví dụ, thay đổi nó chỉ trong tệp beans.xml. –

5

Một khả năng khác sẽ được tạo constructor mặc định không trong lớp xe như thế này:

public Car { 
    private String name = "NormalCar"; 

    public Car(String name) { 
     this.name = name; 
    } 
    ... 
} 

bằng cách loại bỏ constructor mặc định, lớp xe không còn có thể được sử dụng để tạo ra các trường hợp sử dụng bằng cách tiêm.

Và thay đổi phương thức sản xuất của bạn để

@Produces 
public Car getCar() { 
    if(isBatmanCar) { 
     return new Car("BatmanCar"); 
    } 
    return new Car("NormalCar"); 
} 

sau đó phương pháp sản xuất sẽ là cách duy nhất để tạo Ô tô của bạn.

Cách này có thể được sử dụng, khi bạn biết rằng bạn sẽ luôn cần trường hợp tùy chỉnh và bạn không cần hàm tạo mặc định. Nhưng thường thì dung dịch Antoine hữu dụng hơn.

8

Sử dụng @ Tác phẩm thay thế nhưng chỉ nên được sử dụng nếu bạn muốn có thể kích hoạt nó thông qua beans.xml.

Ngăn chặn hàm tạo mặc định của bean cũng hoạt động nhưng bạn sẽ không thể sử dụng bean của mình trong phạm vi khác hơn @RequestScoped.

Sử dụng trình đánh giá của riêng bạn hoạt động nhưng không hữu ích nếu bạn chỉ có một triển khai và chỉ muốn có thể tạo hạt của mình với nhà sản xuất thay vì bằng hàm tạo.

Cách đơn giản nhất là để chú thích đậu của bạn @Any:

@Any 
public class Car { 
} 
... 
@Produces 
public Car getCar() { 
    return new Car(); 
} 
... 
@Inject 
Car car; 

Những điều mà bạn phải lưu ý:

  • Tất cả đậu và các nhà sản xuất luôn ngầm có trình độ @Any
  • Đậu và người sản xuất không có đủ điều kiện rõ ràng đủ điều kiện hoàn toàn @Default
  • Đậu và nhà sản xuất có vòng loại rõ ràng không còn đủ điều kiện IED @Default
  • điểm tiêm mà không cần vòng loại rõ ràng là @Default ngầm có trình độ, nhưng không @Any

Về tất cả điều này, cùng mã vẻ như trên rõ ràng có trình độ như thế này:

@Any 
public class Car { 
} 
... 
@Produces 
@Any 
@Default 
public Car getCar() { 
    return new Car(); 
} 
... 
@Inject 
@Default 
Car car; 

Nó trở nên rõ ràng hơn rằng hàm tạo mặc định của bean không phải là một khả năng hợp lệ cho điểm tiêm và nhà sản xuất là một khả năng hợp lệ.

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