จะฉีดการอ้างอิงลงในวัตถุที่สร้างขึ้นเองในฤดูใบไม้ผลิได้อย่างไร?


128

สมมติว่าเรามีคลาส:

public class MyClass {
    @Autowired private AnotherBean anotherBean;
}

จากนั้นเราสร้างวัตถุของคลาสนี้ (หรือเฟรมเวิร์กอื่น ๆ ได้สร้างอินสแตนซ์ของคลาสนี้)

MyClass obj = new MyClass();

เป็นไปได้ไหมที่จะฉีดการอ้างอิง? สิ่งที่ต้องการ:

applicationContext.injectDependencies(obj);

(ฉันคิดว่า Google Guice มีอะไรแบบนี้)

คำตอบ:


194

คุณสามารถทำได้โดยใช้autowireBean()วิธีการAutowireCapableBeanFactory. คุณส่งผ่านวัตถุโดยพลการและ Spring จะปฏิบัติกับมันเหมือนสิ่งที่สร้างขึ้นเองและจะใช้บิตและชิ้นส่วนต่างๆของการเดินสายอัตโนมัติ

หากต้องการรับสิ่งAutowireCapableBeanFactoryนี้เพียงแค่กำหนดค่าอัตโนมัติว่า:

private @Autowired AutowireCapableBeanFactory beanFactory;

public void doStuff() {
   MyBean obj = new MyBean();
   beanFactory.autowireBean(obj);
   // obj will now have its dependencies autowired.
}

คำตอบที่ดี (+1) นอกจากนี้ยังมีวิธีที่สองที่คุณสามารถกำหนดวิธีการทำงานอัตโนมัติได้: static.springsource.org/spring/docs/3.0.x/javadoc-api/org/…
Sean Patrick Floyd

แต่จะเกิดอะไรขึ้นถ้าฉันมีสองวัตถุและตัวแรกอัตโนมัติที่สอง โรงงานผลิตถั่วอัตโนมัติเกี่ยวข้องกับการอ้างอิงในกรณีอย่างไร?
Vadim Kirilchuk

3
นี่เป็นรูปแบบที่ไม่ดีจริงๆ หากนี่คือวิธีที่คุณใช้ MyBean จริงๆทำไมไม่เพียงแค่มีตัวสร้างที่มี AnotherBean เป็นพารามิเตอร์ สิ่งที่ชอบ: codeส่วนตัว @Autowired AnotherBean bean; โมฆะสาธารณะ doStuff () {MyBean obj = MyBean ใหม่ (bean); } code. ดูเหมือนว่าจะเหมือนกับคำอธิบายประกอบเหล่านี้ที่ผู้คนสับสนจริงๆและอย่าใช้รูปแบบพื้นฐานที่อยู่ใน java SDK ตั้งแต่วันที่ 1 :(
เดนิส

3
ฉันเห็นด้วย - Spring ได้กำหนดภาษาใหม่ทั้งหมด ตอนนี้เราใช้อินเทอร์เฟซเป็นคลาสที่เป็นรูปธรรมวิธีการเป็นอินสแตนซ์ของคลาสและวิธีการที่ซับซ้อนและหนักหน่วงในการทำสิ่งที่คุณเคยทำด้วยการออกแบบใหม่และเหมาะสม
Rodney P. Barbati

@Denis ถ้า MyBean มีการอ้างอิงที่คลาสจริงไม่ต้องการคุณกำลังลงทะเบียนการอ้างอิงที่ไม่มีอยู่จริงเพียงเพื่ออินสแตนซ์คลาสดังนั้นจึงไม่มีความแตกต่างจริงๆ
Dalton

17

คุณยังสามารถทำเครื่องหมาย MyClass ของคุณด้วยคำอธิบายประกอบ @Configurable:

@Configurable
public class MyClass {
   @Autowired private AnotherClass instance
}

จากนั้นในเวลาสร้างมันจะฉีดการอ้างอิงโดยอัตโนมัติ คุณควรมี<context:spring-configured/>ใน xml บริบทแอปพลิเคชันของคุณ


2
Galz666 วิธีการของคุณดูสะอาดกว่าสำหรับสิ่งที่ฉันต้องการทำ อย่างไรก็ตามฉันไม่สามารถใช้งานได้ ฉันไม่มีไฟล์ xml และกำลังใช้การกำหนดค่า Java ทั้งหมด มีเทียบเท่ากับ<context:spring-configured/>?
masstroy

1
นี่เป็นวิธีการแก้ปัญหาที่สะอาด แต่ต้องใช้ความพยายามมากขึ้นเล็กน้อย: คุณควรใช้การทอผ้าตามเวลาโหลดตามที่ iimuhin แสดงไว้ด้านบนหรือเพิ่มคอมไพเลอร์ AspectJ ในโครงการ เวลาในการโหลดตามชื่อที่แนะนำจะทำให้มีค่าใช้จ่ายเพิ่มเติมในขณะรันไทม์
jsosnowski

4

เพียงแค่มีความต้องการเดียวกันและในกรณีของฉันมันก็เป็นตรรกะในคลาส java ที่จัดการได้ของ Spring ที่เข้าถึงApplicationContextได้ แรงบันดาลใจจาก scaffman แก้ไขโดย:

AutowireCapableBeanFactory factory = applicationContext.getAutowireCapableBeanFactory();
factory.autowireBean(manuallyCreatedInstance);

3

ฉันต้องการแบ่งปันวิธีการแก้ปัญหาของฉันที่เป็นไปตาม@Configurableแนวทางที่brieflyกล่าวไว้ในคำตอบ @ glaz666 เพราะ

  • คำตอบโดย @skaffman อายุเกือบ 10 ปีและไม่ได้หมายความว่าไม่ดีพอหรือไม่ทำงาน
  • คำตอบโดย @ glaz666 นั้นสั้นและไม่ได้ช่วยฉันแก้ปัญหาได้จริง แต่ชี้ให้ฉันไปในทิศทางที่ถูกต้อง

การตั้งค่าของฉัน

  1. Spring Boot 2.0.3 ด้วยSpring Neo4j & Aop starts(ซึ่งไม่เกี่ยวข้องอยู่แล้ว)
  2. ใส่ถั่วเมื่อSpring Bootพร้อมโดยใช้@Configurableวิธีการ (ใช้ApplicationRunner)
  3. Gradle & Eclipse

ขั้นตอน

ฉันต้องทำตามขั้นตอนด้านล่างเพื่อให้มันใช้งานได้

  1. @Configurable(preConstruction = true, autowire = Autowire.BY_TYPE, dependencyCheck = false)จะอยู่ด้านบนของของคุณBeanที่จะถูก instantiated ด้วยตนเอง ในกรณีของฉันBeanที่จะสร้างอินสแตนซ์ด้วยตนเองมี@Autowiredบริการดังนั้นอุปกรณ์ประกอบฉากถึงคำอธิบายประกอบด้านบน
  2. ใส่คำอธิบายประกอบหลักของ Spring Boot XXXApplicaiton.java(หรือไฟล์ที่มีคำอธิบายประกอบ@SpringBootApplication) ด้วย@EnableSpringConfiguredและ@EnableLoadTimeWeaving(aspectjWeaving=AspectJWeaving.ENABLED)
  3. เพิ่มการอ้างอิงในไฟล์บิลด์ของคุณ (เช่น build.gradle หรือ pom.xml ขึ้นอยู่กับว่าคุณใช้อันไหน) compile('org.springframework.boot:spring-boot-starter-aop')และcompile('org.springframework:spring-aspects:5.0.7.RELEASE')
  4. ใหม่ + ขึ้นของคุณBeanที่มีการใส่คำอธิบายประกอบกับ@Configurableทุกที่และการอ้างอิงควรจะเป็นแบบอัตโนมัติ

* เกี่ยวกับจุด # 3 ข้างต้นฉันทราบว่าorg.springframework.boot:spring-boot-starter-aopสกรรมกริยาดึงspring-aop(ตามที่แสดงไว้ที่นี่mavencentral ) แต่ในกรณีของฉัน Eclipse ไม่สามารถแก้ไข@EnableSpringConfiguredคำอธิบายประกอบได้ด้วยเหตุนี้ฉันจึงเพิ่มการspring-aopอ้างอิงอย่างชัดเจนนอกเหนือจากตัวเริ่มต้น หากคุณประสบปัญหาเดียวกันเพียงแค่ประกาศการพึ่งพาหรือออกผจญภัยเพื่อค้นหา

  • มีความขัดแย้งของเวอร์ชัน
  • เหตุใดจึงorg.springframework.context.annotation.aspect.*ไม่สามารถใช้งานได้
  • การตั้งค่า IDE ของคุณถูกต้องหรือไม่
  • ฯลฯ เป็นต้น
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.