2011-12-01 11 views
7

Tôi đang cố gắng sử dụng Spring with Scala. Tôi biết Autowired làm việc với lớp Scala, nhưng tôi đang sử dụng một khung công tác web yêu cầu một đối tượng và tôi muốn tiêm một con dao vào nó. Tôi tự hỏi làm thế nào để làm điều này? Xin lỗi, tôi khá mới với Scala, cảm ơn trước.Làm thế nào để sử dụng Spring Autowired (hoặc bằng tay có dây) trong đối tượng Scala?

@Service 
    object UserRest extends RestHelper { 
     @Autowired 
     @BeanProperty 
     val userRepository: UserRepository = null; 

     ..... 
    } 

    <beans> 
     ..... 
     <bean id="userRest" class="com.abc.rest.UserRest" > 
       <!--- this is my attempt to manually wire it ---> 
       <property name="userRepository" ref="userRepository"/> 
     </bean> 
    </beans> 
+0

tại sao bạn cần một đối tượng ở đây? anyway '@Service class Xin chào {@Autowired var repo: Repository = _}' sẽ hoạt động tốt, giả sử bạn đã định cấu hình quét thành phần hoặc sử dụng AnnotationConfigApplicationContext – OlegYch

Trả lời

12

Về cơ bản, bạn có hai vấn đề:

  • tài sản nên có thể thay đổi, ví dụ: var hơn val

  • Tất cả các phương pháp Scala objectstatic, trong khi mùa xuân hy vọng phương pháp dụ. Trên thực tế Scala tạo ra một lớp với các phương thức ví dụ có tên là UserRest$ phía sau khung cảnh, và bạn cần tạo một cá thể đơn lẻ UserRest$.MODULE$ có sẵn cho Spring.
    Mùa xuân có thể áp dụng cấu hình cho các trường hợp singleton từ trước, nhưng chúng phải được trả về bằng một phương thức, trong khi UserRest$.MODULE$ là một trường. Vì vậy, bạn cần phải tạo một phương thức để trả về nó.

Vì vậy, một cái gì đó như thế này nên làm việc:

object UserRest extends RestHelper { 
    @BeanProperty 
    var userRepository: UserRepository = null; 

    def getInstance() = this 
    ... 
} 

.

<bean id="userRest" 
    class="com.abc.rest.UserRest" 
    factory-method = "getInstance"> 
    <property name="userRepository" ref="userRepository"/> 
</bean> 

Bạn có thể thay <property> với @Autowired, nhưng không thể thay thế khai đậu thủ công với @Service do vấn đề với dụ singleton mô tả ở trên.

Xem thêm:

+0

Điều đó khá thú vị. Tôi tự hỏi nếu có một cách không xml làm việc đó với Spring 3.1. – sourcedelica

+0

@ericacm: Trên thực tế, bạn có thể tạo đối tượng '@ Configuration' và trả về' UserRest $ .MODULE $ 'từ phương thức' @ Bean' được chú thích. Nó đã có sẵn trong Spring 3.0. – axtavt

+0

Có - điểm tốt. – sourcedelica

1

Những gì tôi làm là sử dụng AutowiredAnnotationBeanPostProcessor để tiêm đối tượng ở thời gian thi công.

Ví dụ:

object UserRest extends RestHelper { 
    @Autowired 
    var userRepository: UserRepository = _ 

    AppConfig.inject(this) 
} 

@Configuration 
class AppConfig extends ApplicationListener[ContextRefreshedEvent] { 

    // Set the autowiredAnnotationBeanPostProcessor when the Spring context is initialized 
    def onApplicationEvent(event: ContextRefreshedEvent) { 
    autowiredAnnotationBeanPostProcessor = 
     event.applicationContext. 
     getBean(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME). 
      asInstanceOf[AutowiredAnnotationBeanPostProcessor] 
    } 
} 

object AppConfig { 
    var autowiredAnnotationBeanPostProcessor: AutowiredAnnotationBeanPostProcessor = null 

    def inject(obj: AnyRef) { 
    autowiredAnnotationBeanPostProcessor.processInjection(obj); 
    } 
} 

Bây giờ bạn có thể sử dụng AppConfig.inject() để tiêm bất kỳ đối tượng có vòng đời không được kiểm soát bởi Spring. Ví dụ: Thực thể JPA, v.v.

4

Tất cả những gì thực sự cần thiết là bạn xác định đối tượng của mình dưới dạng lớp, chứ không phải đối tượng. Bằng cách đó, Spring sẽ khởi tạo nó.

@Service 
    object UserRest extends RestHelper { 
     @Autowired 
     @BeanProperty 
     val userRepository: UserRepository = null; 

     ..... 
    } 
<beans> 
     ..... 
     <bean id="userRest" class="com.abc.rest.UserRest" > 
       <!--- this is my attempt to manually wire it ---> 
       <property name="userRepository" ref="userRepository"/> 
     </bean> 
    </beans> 

Thay đổi "val" thành "var" là không cần thiết (Spring sử dụng phản chiếu, bỏ qua bất biến). Tôi khá chắc chắn rằng @BeanProperty cũng không cần thiết (Spring sẽ gán cho trường cơ bản, phản ánh).giải pháp

3

axtavt đã không làm việc cho tôi, nhưng kết hợp lời đề nghị khác với câu trả lời khác Tôi nghĩ rằng đây là giải pháp thanh lịch nhất:

object User { 
    @Autowired val repo: UserRepository = null 

    def instance() = this 
} 

@Configuration 
class CompanionsConfig { 
    @Bean def UserCompanion = User.instance 
} 

<context:component-scan base-package="your-package" /> 

Một vài lưu ý:

  • Sử dụng @Configuration Đảm bảo rằng các đối tượng đồng hành của bạn háo hức tự động
  • Sử dụng @Bean def tránh phải xử lý các tên ồn ào Scala cung cấp cho lớp thực hiện đối tượng đồng hành
  • val làm việc tốt, như đã đề cập bởi Dave Griffith
  • không có nhu cầu cho @BeanProperty Scala của, Spring hiểu tính Scala out of the box (Tôi đang sử dụng 3.2.2)
0

Ngoài https://stackoverflow.com/a/8344485/5479289, bạn cũng có thể thêm đối tượng gói scala vào ngữ cảnh mùa xuân, cũng như đối tượng scala, sử dụng phương pháp nhà máy. Đối tượng gói được biên dịch là lớp java thông thường có tên là gói, vì vậy bạn có thể thêm nó vào ngữ cảnh Mùa xuân. Sau đó bạn sẽ có khả năng tất cả của mùa xuân bên trong đối tượng này, tức là @Autowired, @value, thủ công hệ thống dây điện, vv

gói thử nghiệm:

package my.module 

package object A { 
    def getInstance = this 

    @Autowired 
    private val b: B = null 
} 

Và mùa xuân bối cảnh xml là:

<beans ...> 
    ... 
    <bean id="a" class="my.module.A.package" factory-method="getInstance"/> 
    ... 
</beans>