2017-11-03 15 views
8

Sử dụng Spring 3.X.X Tôi có 2 dịch vụ được chú thích bằng @Primary và tôi đã tạo một lớp cấu hình khác nơi tôi muốn sử dụng phiên bản "tùy chỉnh" của một trong các dịch vụ.Ghi đè cấu hình bean cài đặt cấu hình "Chính"

Vì lý do nào đó, tôi bỏ qua trong khi gỡ lỗi lớp cấu hình Tôi thấy rằng nó nhận được các phụ thuộc chính xác nhưng khi tôi muốn sử dụng nó, nó đã thiết lập sai.

Tôi tìm thấy nó dễ dàng hơn để giải thích với mã, đây là một ví dụ:

Interface Foo:

public interface Foo { 
    String getMessage(); 
} 

thực hiện Tiểu học với một thông điệp mặc định hardcoded:

giao diện
@Primary 
@Service("FooImpl") 
public class FooImpl implements Foo { 

    private String message = "fooDefaultMessage"; 

    @Override 
    public String getMessage() { 
     return message; 
    } 

    public void setMessage(String message) { 
     this.message = message; 
    } 
} 

Bar:

public interface Bar { 

    void doBar(); 
} 

Thực hiện mặc định của thanh:

@Primary 
@Service("BarImpl") 
public class BarImpl implements Bar { 

    private Foo foo; 

    @Override 
    public void doBar() { 
     System.out.println(foo.getMessage()); 
    } 

    public Foo getFoo() { 
     return foo; 
    } 

    @Autowired 
    public void setFoo(Foo foo) { 
     this.foo = foo; 
    } 
} 

Cho đến giờ rất tốt, nếu tôi muốn Tiêm một thanh, tôi sẽ nhận được mọi thứ như mong đợi. Thing là tôi có một cấu hình với những điều sau đây:

@Configuration 
public class BeanConfiguration { 

    @Bean 
    @Qualifier("readOnlyFoo") 
    Foo readOnlyFoo() { 
     FooImpl foo = new FooImpl(); 
     foo.setMessage("a read only message"); 
     return foo; 
    } 

    @Bean 
    @Qualifier("readOnlyBar") 
    Bar readOnlyBar() { 
     BarImpl bar = new BarImpl(); 
     bar.setFoo(readOnlyFoo()); 
     return bar; 
    } 
} 

Khi tôi muốn tiêm một readOnlyBar tôi nhận được Foo mặc định thay vì một thiết lập ở đây.

private Bar readOnlyBar; 

@Autowired 
@Qualifier("readOnlyBar") 
public void setReadOnlyBar(Bar readOnlyBar) { 
    this.readOnlyBar = readOnlyBar; 
} 

... 
readOnlyBar.doBar(); 

Có đậu Foo với "fooDefaultMessage". Tại sao vậy? Làm cách nào để đảm bảo Spring sử dụng Bean I được đặt trên @Configuration?

Cảm ơn trước,

EDIT: Lưu ý rằng tương tự xảy ra nếu thay vì gọi phương thức ReadOnly() trong lớp @Configuration bạn vượt qua một đối số @Qualified. tức là:

@Configuration 
public class BeanConfiguration { 

    @Bean 
    @Qualifier("readOnlyFoo") 
    Foo readOnlyFoo() { 
     FooImpl foo = new FooImpl(); 
     foo.setMessage("a read only message"); 
     return foo; 
    } 

    @Bean 
    @Qualifier("readOnlyBar") 
    Bar readOnlyBar(@Qualifier("readOnlyFoo") Foo readOnlyFoo) { 
     BarImpl bar = new BarImpl(); 
     bar.setFoo(readOnlyFoo); 
     return bar; 
    } 
} 

Nếu thay vào đó, tôi thử sử dụng công cụ tiêm phụ thuộc vào Constructor, tôi không thể sử dụng.

+0

bạn không thể sử dụng hồ sơ cho điều này? –

+0

Bạn không chắc chắn cách cấu hình sẽ trợ giúp ở đây. Có, tôi có thể có một cấu hình bằng cách sử dụng các triển khai mặc định và một cấu hình khác trỏ đến các cấu hình chỉ đọc. Câu hỏi là làm thế nào để thiết lập chỉ đọc một instantiating mới (chỉ đọc) đậu từ mặc định. – void

Trả lời

2

Bạn không thể sử dụng @Autowired trên biến mẫu và đặt trong phương thức @Bean như bạn đã làm. Một phần của vòng đời mùa xuân đi theo cách này

định nghĩa

Bean quét => trường hợp Bean tạo => Bài xử lý gọi => .....

Trong ví dụ của bạn,

@Bean 
@Qualifier("readOnlyBar") 
Bar readOnlyBar() { 
    BarImpl bar = new BarImpl(); 
    bar.setFoo(readOnlyFoo()); 
    return bar; 
} 

readOnlyBar đậu được được tạo và bởi vì readOnlyFoo() được gọi từ bên trong phương thức này, hạt readOnlyFoo cũng được khởi tạo. Đến thời điểm này, readOnlyBarreadOnlyFoo trong biến đối tượng của nó. Khi đậu được khởi tạo, AutowiredAnnotationBeanPostProcessor được gọi là quét lớp đậu (BarImpl trong trường hợp này) cho bất kỳ chú thích @Autowired nào về các biến hoặc phương pháp mẫu.Nó tìm thấy chúng và cố gắng tiêm đậu vào các biến tương ứng bằng cách sử dụng tiêm trường hoặc tiêm setter (bất cứ nơi nào có chú thích @Autowired). Trong trường hợp này kể từ khi chúng tôi có thiết lập @Autowired và không chỉ định chú thích @Qualifier, mùa xuân sẽ chèn đậu @Primary là hạt defaultFooMessage.

AFAIK, không có cách nào đơn giản để định cấu hình vào mùa xuân cho các phương thức @Bean được ưu tiên hơn Autowiring.

Lập tức tất cả các hạt với phương pháp @Bean sẽ khắc phục sự cố.

2

Thường thì tốt hơn nên sử dụng @Bean ("beanName") thay vì hai chú thích: Bean và Qualifier. Và tôi không chắc Qualifier có hoạt động để đặt tên đậu hay không. Dù sao, bạn nên viết mã theo một kiểu. Vì vậy, nếu bạn sử dụng thuộc tính value trong chú thích @Service, bạn nên sử dụng thuộc tính value trong chú giải @Bean.

Tạo trường @Autowired List<Foo> allFoos và xem trong chế độ gỡ lỗi. Bạn sẽ thấy tất cả các bạn đậu Foo để bạn có thể kiểm tra tên của họ.

2

Khi @yaswanth chỉ ra trong câu trả lời của mình, vấn đề là tài sản foo đã bị ghi đè bởi việc tiêm tài sản xảy ra sau khi tạo bean.

Một cách để khắc phục đó là sử dụng chức năng tiêm xây dựng cho BarImpl thay vì phun thuộc tính. Điều đó sẽ làm cho cái nhìn mã của bạn như ...

@Primary @Service("BarImpl") 
class BarImpl implements Bar 
{ 
    private Foo foo; 

    @Autowired 
    public BarImpl(Foo foo) { 
     this.foo = foo; 
    } 
} 

và cấu hình của bạn sẽ là ...

@Configuration 
class BeanConfiguration 
{ 
    @Bean @Qualifier("readOnlyFoo") 
    Foo readOnlyFoo() { 
     FooImpl foo = new FooImpl(); 
     foo.setMessage("a read only message"); 
     return foo; 
    } 

    @Bean @Qualifier("readOnlyBar") 
    Bar readOnlyBar(@Qualifier("readOnlyFoo") Foo readOnlyFoo) { 
     return new BarImpl(readOnlyFoo); 
    } 
} 

Là một ca khúc bên; bạn cũng nên đảm bảo sử dụng tiêm phụ thuộc trong các phương pháp nhà máy của bạn thay vì gọi phương thức nhà máy một cách rõ ràng, hoặc bạn sẽ kết thúc với nhiều trường hợp của hạt ...

Chúc may mắn với những nỗ lực trong tương lai của bạn!

+0

Mặc dù tôi biết điều này, vì nó được viết trong câu hỏi, nó là câu trả lời gần nhất với những gì tôi cần và tiền thưởng sắp kết thúc, do đó tôi đã chọn câu trả lời này để nhận tiền thưởng. – void

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