2013-02-18 22 views
8

Tôi thấy một số hành vi kỳ lạ, tôi hy vọng một người nào đó ở đây có thể tỏa sáng một chút về vấn đề này.Vấn đề JavaConfig và CustomScopeConfigurer của Spring

Hãy để tôi bắt đầu bằng cách mô tả thiết lập của tôi. Đầu tiên, một dữ liệu đơn giản đối tượng

public class Apple { 
    private String name; 
    public Apple withName(String name) { 
     this.name = name; 
     return this; 
    } 
    public String getName() { 
     return name; 
    } 
} 

Và một lớp thử nghiệm ..

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(classes={TestConfig.class}) 
public class AppleTest { 
    @Autowired private Apple apples; 

    @Test 
    public void simpleTest() { 
     System.out.println("OBJ: "+apples); 
    } 
} 

Các cấu hình như sau

@Configuration 
public interface ConfigInterface { 
    public Apple getApple(); 
} 

Với một lớp học thực hiện

@Configuration 
@Import(AbstractTestConfig.class) 
public class TestConfig implements ConfigInterface { 
    public Apple getApple() { 
     return new Apple().withName("Granny apples"); 
    } 
} 

Với phụ thuộc cấu hình ...

@Configuration 
public class AbstractTestConfig { 
    @Autowired ConfigInterface conf; 

    @Bean Apple myTestApple() { 
     return conf.getApple(); 
    } 
} 

Tất cả các công trình này đều tuyệt vời. Tôi chạy thử nghiệm, tôi thấy đầu ra tôi mong đợi. Nhưng sau đó tôi ném một cờ lê vào bánh xe và sửa đổi AbstractTestConfig để trông như sau.

@Configuration 
public class AbstractTestConfig { 
    @Autowired ConfigInterface conf; 

    @Bean Apple myTestApple() { 
     return conf.getApple(); 
    } 

    // NEW CODE 
    @Bean CustomScopeConfigurer scopeConfigurer() { 
     return new CustomScopeConfigurer(); 
    } 
} 

Và tất cả của một đột ngột các @Autowired đối tượng conf là null khi nó là cần thiết để xây dựng các đậu Apple.

Kỳ lạ hơn nữa, nếu tôi di chuyển hạt CustomScopeConfigurer sang lớp TestConfig, thì nó hoạt động.

Có điều gì tôi không biết về phạm vi hoặc đối tượng CustomScopeConfigurer nói riêng không?

Trả lời

16

sao chép từ mùa xuân @Bean javadoc:

BeanFactoryPostProcessor-trở về phương pháp @Bean

xem xét đặc biệt phải được thực hiện cho các phương pháp @Bean mà trở về mùa xuân BeanFactoryPostProcessor (BFPP) các loại. Vì các đối tượng BFPP phải được khởi tạo rất sớm trong vòng đời của thùng chứa, chúng có thể can thiệp vào việc xử lý các chú thích như @Autowired, @Value và @PostConstruct trong các lớp @Configuration. Để tránh các vấn đề về vòng đời này, hãy đánh dấu các phương thức @Bean trả về BFPP là tĩnh. Ví dụ:

@Bean 
public static PropertyPlaceholderConfigurer ppc() { 
    // instantiate, configure and return ppc ... 
} 

Bằng cách đánh dấu phương pháp này như tĩnh, nó có thể được gọi mà không gây ra instantiation của tuyên bố @Configuration các lớp học, như vậy tránh được những mâu thuẫn vòng đời nêu trên. Tuy nhiên, lưu ý rằng các phương thức @Bean tĩnh sẽ không được tăng cường cho các thuật ngữ phạm vi và ngữ nghĩa AOP như đã đề cập ở trên. Điều này làm việc trong các trường hợp BFPP, vì chúng thường không được tham chiếu bởi các phương thức @Bean khác. Như một lời nhắc nhở, một thông điệp tường trình mức WARN sẽ được ban hành cho bất kỳ phương thức @Bean không tĩnh nào có kiểu trả về gán cho BeanFactoryPostProcessor.

0

Sau khi cẩn thận rà soát các dữ liệu ghi nhận mùa xuân, tôi bắt gặp vị cứu tinh nhỏ này:

[junit] 1141 [main] WARN org.springframework.context.annotation.ConfigurationClassEnhancer - @Bean method AbstractTestConfig.scopeConfigurer is non-static and returns an object assignable to Spring's BeanFactoryPostProcessor interface. This will result in a failure to process annotations such as @Autowired, @Resource and @PostConstruct within the method's declaring @Configuration class. Add the 'static' modifier to this method to avoid these container lifecycle issues; see @Bean Javadoc for complete details 

Tôi thực sự không hiểu tại sao có nó như tĩnh làm cho một sự khác biệt mặc dù.

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