2015-04-27 16 views
5

Tôi có tình huống như thế này. Tôi không thể thấy bất kỳ lỗi nào nhưng tôi không nhận được kết quả của mình.Xử lý phụ thuộc vòng tròn trong CDI

@ApplicationScoped 
public class A { 

    private B b; 


    @Inject 
    public A(B b) { 
     this.b = b; 
    } 
} 

@Singleton 
public class B { 

    private A a; 


    @Inject 
    public B(A a) { 
     this.a = a; 
    } 
} 

Loại tiêm phụ thuộc này có sai không?

Bất kỳ ai cũng có thể giúp tôi với điều này.

+0

Bạn cần phải cấu trúc lại, di chuyển mã phụ thuộc khỏi các lớp A và B này và tạo lớp C. –

+0

@ André. Cảm ơn vi đa trả lơi. Bạn có thể nói cách A và B này gọi từ C – Patan

+0

CDI không thể xử lý phụ thuộc vòng tròn, EJB có thể – maress

Trả lời

3

Tôi muốn tránh sự phụ thuộc vòng tròn này, có một vài lý do để làm điều đó.

Nhận xét về this article

Một constructor lộn xộn là một dấu hiệu. Nó cảnh báo tôi rằng lớp học của tôi đang trở thành một khối nguyên khối, đó là một jack của tất cả các ngành nghề và một bậc thầy của không. Nói cách khác, một nhà xây dựng lộn xộn thực sự là một điều tốt. Nếu tôi cảm thấy rằng các nhà xây dựng của một lớp học là quá lộn xộn, tôi biết rằng đó là thời gian để làm một cái gì đó về nó.

this one

Bạn sẽ tìm thấy trường hợp một lớp A cần một thể hiện của B và B cần một thể hiện của A. Đây là một trường hợp điển hình của một phụ thuộc vòng tròn và rõ ràng là xấu. Theo kinh nghiệm của tôi, giải pháp là làm cho B trở thành một phần của A khi hai người phụ thuộc quá mạnh đến nỗi họ thực sự nên là một lớp. thường xuyên hơn dù có thêm ít nhất một C ẩn lớp trong đó để B không cần A nhưng chỉ C.

Như Oliver Gerke commented:

Đặc biệt constructor injection thực sự ngăn cản bạn giới thiệu các phụ thuộc cyclic. Nếu bạn giới thiệu chúng, bạn về cơ bản làm cho hai bên một bởi vì bạn không thể thực sự thay đổi một mà không có nguy cơ để phá vỡ khác, mà trong mọi trường hợp là một mùi thiết kế.

Đây là một ví dụ nhỏ về những gì tôi có thể làm.

public class A { 

    private B b; 

    @Autowired 
    public A(B b) { 
     this.b = b; 
    } 

    public void doSomeWork() { 
     // WORK 
    } 

    public void doSomeWorkWithB() { 
     b.doSomeWork(); 
    } 
} 

public class B { 

    private A a; 

    @Autowired 
    public B(A a) { 
     this.a = a; 
    } 

    public void doSomeWork() { 
     // WORK 
    } 

    public void doSomeWorkWithA() { 
     a.doSomeWork(); 
    } 

} 

Sau khi tái cấu trúc, nó có thể trông như thế này.

public class A { 

    private C c; 

    @Autowired 
    public A(C c) { 
     this.c = c; 
    } 

    public void doSomeWork() { 
     // WORK 
    } 

    public void doSomeWorkWithC() { 
     c.doSomeWorkThatWasOnA(); 
    } 

} 

public class B { 

    private C c; 

    @Autowired 
    public B(C c) { 
     this.c = c; 
    } 

    public void doSomeWork() { 
     // WORK 
    } 

    public void doSomeWorkWithC() { 
     c.doSomeWorkThatWasOnB(); 
    } 

} 

public class C { 

    public void doSomeWorkThatWasOnB() { 
     // WORK 

    } 

    public void doSomeWorkThatWasOnA() { 
     // WORK 
    } 

} 
+1

Có rất nhiều đọc mà bạn có thể làm trên các liên kết tôi đăng, đọc và mã hóa hạnh phúc! : D –

+0

Cảm ơn bạn rất nhiều. Bạn có thể nói làm thế nào tôi sẽ gọi một số phương pháp từ C. Hoặc tôi sẽ phải sao chép tất cả các logic có? – Patan

+0

Bạn cấu trúc lại mã từ A và B sao cho không có cuộc gọi nào từ A đến B và B đến A, chuyển logic sang C –

0

Bạn cũng có thể sử dụng Setter based Dependency Injection để giải quyết vấn đề này.

+0

Làm thế nào mà Cứu giúp? –

+0

Nếu bạn có sự phụ thuộc Tiêm thông qua hàm tạo, ClassA cần ClassB và ClassB cần ClassA để được khởi tạo, điều này tạo ra một phụ thuộc vòng tròn. Nếu bạn sử dụng DI dựa trên setter, hoặc classA hoặc ClassB được khởi tạo trước, sau đó các đối tượng instantiated được sử dụng để thiết lập thuộc tính của nhau phá vỡ sự phụ thuộc cyclic. –

+0

Đó không phải là vấn đề. Xem câu trả lời của tôi. –

2

Trích dẫn từ Phần 5 của CDI Specification 1.2:

Các container được yêu cầu hỗ trợ circularities trong sự phụ thuộc đồ thị đậu nơi ít nhất một đậu tham gia mỗi chuỗi tròn phụ thuộc có bình thường phạm vi, như được định nghĩa trong Phạm vi thông thường và phạm vi giả. Thùng chứa không được yêu cầu để hỗ trợ chuỗi vòng phụ thuộc mà mỗi hạt tham gia trong chuỗi có phạm vi giả.

ApplicationScoped là phạm vi bình thường, vì vậy chu trình này sẽ hoạt động.

Trong mẫu của bạn, lớp A không thể được ủy quyền vì nó thiếu một hàm tạo không đối số. Thêm hàm tạo này (có thể đã được bảo vệ hoặc hiển thị gói), mẫu của bạn triển khai không có vấn đề gì.

+0

Điều này giải quyết một cách chính xác vấn đề, nếu lớp 'A' bị thiếu thì đó là hàm tạo no-arg trên nguồn của Patan. –

0

Chắc chắn có một giải pháp cho việc này. Hãy để tôi quote bản thân mình:

Giải pháp đúng là tiêm javax.enterprise.inject.Instance, trong đó T là loại của lớp được tiêm. Vì kiểu này là trực tiếp Foo, việc gọi phương thức get() trên một đối tượng được đánh máy là Instance được bảo đảm để tiêm đối tượng thích hợp mọi lúc. Cách tiếp cận này hoạt động rất tốt, bởi vì cá thể được lấy tự động từ thùng chứa bởi bản thân việc triển khai thực hiện và chỉ khi cần thiết. Do đó, trách nhiệm truy xuất phụ thuộc được để lại cho mã của bạn - mã của bạn có trách nhiệm không tạo ra vòng lặp vô tận.

@Named 
public class Foo implements Fooable{ 

@Inject 
private Instance<Foo> foo; 

public void executeFirst(){ 
foo.get().executeSecond(); 
} 

@Transactional 
public void executeSecond(){ 
//do something 
} 

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