Spring รับ ApplicationContext ปัจจุบัน


107

ฉันใช้ Spring MVC สำหรับเว็บแอปพลิเคชันของฉัน ถั่วของฉันเขียนในspring-servlet.xmlไฟล์ ""

ตอนนี้ฉันมีคลาสMyClassแล้วและฉันต้องการเข้าถึงคลาสนี้โดยใช้ถั่วสปริง

ในspring-servlet.xmlฉันได้เขียนต่อไปนี้

<bean id="myClass" class="com.lynas.MyClass" />

ตอนนี้ฉันต้องการเข้าถึงสิ่งนี้โดยใช้ไฟล์ ApplicationContext

ApplicationContext context = ??

เพื่อที่ฉันจะได้ทำ

MyClass myClass = (MyClass) context.getBean("myClass");

ทำอย่างไร ??


3
@Autowired MyClass myClass ควรทำงาน!
Mannekenpix

คำตอบ:


163

ฉีดง่ายๆเลย ..

@Autowired
private ApplicationContext appContext;

หรือใช้อินเทอร์เฟซนี้: ApplicationContextAware


อาจจะใช้งานได้: stackoverflow.com/questions/11682858/…
gipinani

ApplicationContextProvider.javaคำตอบต่อไปนี้ดูเหมือนจะเป็นคำตอบที่น่าเชื่อถือที่สุดสำหรับสิ่งนี้
Ionut

1
มันกลับมาเป็น NULL ทุกครั้ง ที่จะพูดถึงที่นี่ว่าฉันกำลังทำสิ่งนี้ในคลาสปกติที่ไม่ใช่ทั้ง "@RestController" หรือ "@Component"
zulkarnain shah

1
ตามเอกสาร Spring ควรหลีกเลี่ยง @Autowired เนื่องจากปัญหาบางประการ นี่คือลิงค์spring.io/understanding/application-context ตัวเลือกที่ดีที่สุดคือการใช้อินเทอร์เฟซ ApplicationContextAware
Durja Arai

89

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

สร้างคลาสใหม่ ApplicationContextProvider.java

package com.java2novice.spring;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class ApplicationContextProvider implements ApplicationContextAware{

    private static ApplicationContext context;

    public static ApplicationContext getApplicationContext() {
        return context;
    }

    @Override
    public void setApplicationContext(ApplicationContext ac)
            throws BeansException {
        context = ac;
    }
}

เพิ่มรายการใน application-context.xml

<bean id="applicationContextProvider"
                        class="com.java2novice.spring.ApplicationContextProvider"/>

ในกรณีคำอธิบายประกอบ (แทน application-context.xml)

@Component
public class ApplicationContextProvider implements ApplicationContextAware{
...
}

รับบริบทเช่นนี้

TestBean tb = ApplicationContextProvider.getApplicationContext().getBean("testBean", TestBean.class);

ไชโย !!


1
ฉันเขียนโค้ดคล้ายกับวิเวก แต่ฉันหลีกเลี่ยงการสร้าง ApplicationContextProvider () ใหม่ทุกครั้งที่ต้องเรียก getBean () จากบริบท สิ่งที่ฉันทำคือต้องมีวิธีการคงที่ ApplicationContextProvider.getApplicationContext()จากนั้นเมื่อถึงเวลาที่ต้องใช้บริบทของแอปในปัจจุบันฉันจึงเรียก:ApplicationContextProvider appContext = ApplicationContextProvider.getApplicationContext()
Panini Luncher

1
ใช่ Panini Luncher นั่นก็ยังดี ตามคำแนะนำของคุณฉันจะเปลี่ยนเป็นแบบนั้น :)
วิเวก

4
Add @Componenton ApplicationContextProviderสามารถหลีกเลี่ยงการกำหนดค่าในaplication-context.xml
bluearrow

1
หมายเหตุ: ควรซิงโครไนซ์ getter และ setter ของบริบท คุณจะไม่ต้องปวดหัวมากเป็นพิเศษสำหรับการทดสอบหน่วย / บูรณาการ ในกรณีของฉัน ApplicationContextProvider ที่คล้ายกันมีบริบทเก่า (จากการทดสอบการรวมก่อนหน้านี้) ซึ่งทำให้เกิดข้อบกพร่องที่ยุ่งยากมากมาย
Oleksandr_DJ

44

ในกรณีที่คุณต้องการเข้าถึงบริบทจากภายในHttpServlet ซึ่งไม่ได้สร้างอินสแตนซ์โดย Spring (ดังนั้นทั้ง @Autowire หรือ ApplicationContextAware จะไม่ทำงาน) ...

WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());

หรือ

SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);

สำหรับคำตอบอื่น ๆ ให้คิดให้ดีก่อนที่จะทำสิ่งนี้:

new ClassPathXmlApplicationContext("..."); // are you sure?

... เนื่องจากสิ่งนี้ไม่ได้ให้บริบทปัจจุบันแก่คุณ แต่มันจะสร้างตัวอย่างอื่นให้คุณ ซึ่งหมายความว่า 1) หน่วยความจำส่วนใหญ่และ 2) ถั่วจะไม่ถูกใช้ร่วมกันระหว่างสองบริบทของแอปพลิเคชันนี้


SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext (this) - ทำงานให้ฉันในเมธอด init () ของตัวกรองการดำเนินการพอร์ตเล็ต Liferay
Igor Baiborodine

เยี่ยมมาก processInjectionBasedOnCurrentContext ทำงานทั้งหมดที่ฉันต้องการ ขอบคุณมาก @Jaroslav
Jad B.

ApplicationContextAware ทำงานสำหรับฉันเมื่อมีการใส่คำอธิบายประกอบด้วย @Component เช่นเดียวกับในโซลูชันของ Vivek (ฉันกำลังเริ่มต้นบริบท Spring ด้วยตนเองผ่านการขยาย AbstractContextLoaderInitializer / createRootApplicationContext)
hello_earth

ขอเตือน ... SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext (this); ไม่ได้เกิดขึ้นทันทีดังนั้นคุณจึงไม่สามารถใช้เป็นบรรทัดแรกในตัวสร้างของคุณได้
SledgeHammer

สิ่งนี้ทำงานได้อย่างสมบูรณ์แบบในเว็บแอป Java แบบคลาสสิก (ไม่ใช่ Spring-mvc ที่จัดการ)
lainatnavi

31

หากคุณใช้คลาสที่ไม่ได้สร้างอินสแตนซ์โดย Spring เช่น JsonDeserializer คุณสามารถใช้:

WebApplicationContext context = ContextLoader.getCurrentWebApplicationContext();
MyClass myBean = context.getBean(MyClass.class);

8
มันไม่ได้ผลกับฉัน ชั้นเรียนของฉันไม่อยู่ในบริบทของฤดูใบไม้ผลิ ฉันพยายามใช้รหัสของคุณ แต่ให้ค่าว่างเป็นค่าตอบกลับ ฉันกำลังพูดถึงContextLoader.getCurrentWebApplicationContext()
R.Karlus

9

เพิ่มสิ่งนี้ลงในรหัสของคุณ

@Autowired
private ApplicationContext _applicationContext;

//Add below line in your calling method
MyClass class = (MyClass) _applicationContext.getBean("myClass");

// Or you can simply use this, put the below code in your controller data member declaration part.
@Autowired
private MyClass myClass;

สิ่งนี้จะฉีด myClass ลงในแอปพลิเคชันของคุณ


6

ตามคำตอบของ Vivek แต่ฉันคิดว่าสิ่งต่อไปนี้จะดีกว่า:

@Component("applicationContextProvider")
public class ApplicationContextProvider implements ApplicationContextAware {

    private static class AplicationContextHolder{

        private static final InnerContextResource CONTEXT_PROV = new InnerContextResource();

        private AplicationContextHolder() {
            super();
        }
    }

    private static final class InnerContextResource {

        private ApplicationContext context;

        private InnerContextResource(){
            super();
        }

        private void setContext(ApplicationContext context){
            this.context = context;
        }
    }

    public static ApplicationContext getApplicationContext() {
        return AplicationContextHolder.CONTEXT_PROV.context;
    }

    @Override
    public void setApplicationContext(ApplicationContext ac) {
        AplicationContextHolder.CONTEXT_PROV.setContext(ac);
    }
}

การเขียนจากวิธีการอินสแตนซ์ไปยังฟิลด์แบบคงที่เป็นแนวทางปฏิบัติที่ไม่ดีและเป็นอันตรายหากมีการจัดการอินสแตนซ์หลายรายการ


มีorg.springframework.core.io.ContextResourceอินเตอร์เฟซ ฉันขอแนะนำให้เลือกชื่ออื่นสำหรับชั้นในContextResourceเพื่อหลีกเลี่ยงความยุ่งเหยิง
Alexander Radchenko

@AlexanderRadchenko ตกลงฉันเปลี่ยนเป็น InnerContextResource
Juan

1

มีหลายวิธีในการรับบริบทของแอปพลิเคชันในแอปพลิเคชัน Spring สิ่งเหล่านี้ได้รับการร้อง:

  1. ผ่าน ApplicationContextAware :

    import org.springframework.beans.BeansException;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    
    public class AppContextProvider implements ApplicationContextAware {
    
    private ApplicationContext applicationContext;
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    }

นี่คือsetApplicationContext(ApplicationContext applicationContext)วิธีการที่คุณจะได้รับ ApplicationContext

  1. ผ่านระบบอัตโนมัติ :

    @Autowired
    private ApplicationContext applicationContext;

@Autowiredคำหลักที่นี่จะให้ applicationContext

สำหรับข้อมูลเพิ่มเติมโปรดไปที่หัวข้อนี้

ขอบคุณ :)


0

อีกวิธีหนึ่งคือการฉีด applicationContext ผ่าน servlet

นี่คือตัวอย่างวิธีการแทรกการอ้างอิงเมื่อใช้บริการเว็บ Spring

<servlet>
        <servlet-name>my-soap-ws</servlet-name>
        <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
        <init-param>
            <param-name>transformWsdlLocations</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:my-applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>5</load-on-startup>

</servlet>

วิธีอื่นคือเพิ่มบริบทของแอปพลิเคชันใน web.xml ของคุณดังที่แสดงด้านล่าง

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>
        /WEB-INF/classes/my-another-applicationContext.xml
        classpath:my-second-context.xml
    </param-value>
</context-param>

โดยทั่วไปคุณพยายามบอก servlet ว่าควรมองหา bean ที่กำหนดไว้ในไฟล์บริบทเหล่านี้


0

ขั้นตอนที่ 1 : ใส่รหัสต่อไปนี้ในชั้นเรียน

@Autowired
private ApplicationContext _applicationContext;

ขั้นตอนที่ 2 : เขียน Getter & Setter

ขั้นตอนที่ 3 : กำหนด autowire = "byType" ในไฟล์ xml ที่กำหนด bean


0

แม้ว่าจะเพิ่ม @Autowire แล้วถ้าคลาสของคุณไม่ใช่ RestController หรือ Configuration Class วัตถุ applicationContext ก็มาเป็น null พยายามสร้างชั้นเรียนใหม่ด้วยด้านล่างและใช้งานได้ดี:

@Component
public class SpringContext implements ApplicationContextAware{

   private static ApplicationContext applicationContext;

   @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws 
     BeansException {
    this.applicationContext=applicationContext;
   }
 }

จากนั้นคุณสามารถใช้เมธอด getter ในคลาสเดียวกันตามความต้องการของคุณเช่นรับการอ้างอิงคลาส Implemented โดย:

    applicationContext.getBean(String serviceName,Interface.Class)

-11
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("/spring-servlet.xml");

จากนั้นคุณสามารถดึงถั่ว:

MyClass myClass = (MyClass) context.getBean("myClass");

ข้อมูลอ้างอิง: springbyexample.org


25
คำตอบนี้ไม่ได้ให้บริบทปัจจุบันแต่เป็นการสร้างอินสแตนซ์อื่นแทน
Jaroslav Záruba
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.