سؤال

هل هناك طريقة محليا/عالميا طلب نسخة من ApplicationContext في الربيع ؟

على افتراض الطبقة الرئيسية يبدأ تهيئة التطبيق السياق أنها لا تحتاج إلى أن تمر عبر الاستدعاءات إلى أي من الفئات التي تحتاج إليها ، أو هل هناك طريقة لفئة لطلب إنشاؤها مسبقا السياق ؟ (والتي أفترض أن يكون المفرد?)

هل كانت مفيدة؟

المحلول

إذا كان الكائن الذي يحتاج إلى الوصول إلى حاوية الفول في وعاء ، فقط تنفيذ BeanFactoryAware أو ApplicationContextAware الواجهات.

إذا كان كائن خارج الحاوية يحتاج إلى الوصول إلى الحاوية ، لقد استعملت معيار صندوق القناص نمط المفرد عن الربيع الحاوية.بهذه الطريقة يكون لديك واحد فقط المفرد في التطبيق الخاص بك ، والباقي كلها المفرد الفاصوليا في وعاء.

نصائح أخرى

يمكنك تنفيذ ApplicationContextAware أو مجرد استخدام @Autowired:

public class SpringBean {
  @Autowired
  private ApplicationContext appContext;
}

SpringBean سوف يكون ApplicationContext حقن داخل هذا الفول هو مثيل.على سبيل المثال إذا كان لديك تطبيق ويب مع معيار جميلة السياقات الهرمي:

main application context <- (child) MVC context

و SpringBean أعلن الرئيسية داخل السياق ، سيكون لها الرئيسية السياق حقن;وإلا لو كان أعلن في MVC السياق ، سيكون لها MVC السياق حقن.

هنا طريقة لطيفة (ليس لي ، المرجع الأصلي هنا:http://sujitpal.blogspot.com/2007/03/accessing-spring-beans-from-legacy-code.html

لقد استعملت هذا النهج وأنه يعمل بشكل جيد.أساسا انها بسيطة الفول الذي يحمل (ثابت) إشارة إلى سياق التطبيق.قبل الرجوع في الربيع التكوين هو تهيئة.

نلقي نظرة على المرجع الأصلي, انها واضحة جدا.

أعتقد أنك يمكن أن تستخدم SingletonBeanFactoryLocator.على beanRefFactory.xml الملف يعقد الفعلية applicationContext ، فإنه يذهب شيء من هذا القبيل:

<bean id="mainContext" class="org.springframework.context.support.ClassPathXmlApplicationContext">
     <constructor-arg>
        <list>
            <value>../applicationContext.xml</value>
        </list>
     </constructor-arg>
 </bean>

و رمز للحصول على الفول من applicationcontext من أينما سيكون شيئا مثل هذا:

BeanFactoryLocator bfl = SingletonBeanFactoryLocator.getInstance();
BeanFactoryReference bf = bfl.useBeanFactory("mainContext");
SomeService someService = (SomeService) bf.getFactory().getBean("someService");

الربيع فريق تشجيع استخدام هذه الفئة و yadayada ، لكنه لم يناسبني جيدا حيث كنت قد استخدمت.

قبل تنفيذ أي من الاقتراحات الأخرى ، اسأل نفسك هذه الأسئلة...

  • لماذا أنا أحاول الحصول على ApplicationContext?
  • أنا فعليا باستخدام ApplicationContext كخدمة محدد ؟
  • يمكن تجنب الوصول إلى ApplicationContext في كل شيء ؟

الأجوبة على هذه الأسئلة هي أسهل في أنواع معينة من التطبيقات (تطبيقات الويب ، على سبيل المثال) مما هي في بلدان أخرى ، ولكن تستحق يسأل على أي حال.

الوصول إلى ApplicationContext هل نوع من انتهاك كله حقن التبعية من حيث المبدأ ، ولكن في بعض الأحيان كنت قد حصلت على الكثير من الخيارات.

إذا كنت تستخدم التطبيق على شبكة الإنترنت كما أن هناك طريقة أخرى للوصول إلى التطبيق السياق دون استخدام ووحدانية باستخدام servletfilter و ThreadLocal.في فلتر يمكنك الوصول إلى التطبيق السياق باستخدام WebApplicationContextUtils وتخزينها إما تطبيق السياق أو حاجة الفول في TheadLocal.

تنبيه:إذا كنت قد نسيت أن ضبطه ThreadLocal سوف تحصل على المشاكل سيئة عند محاولة undeploy التطبيق!وبالتالي ، يجب تعيين والبدء فورا في محاولة أن unsets على ThreadLocal في النهاية-الجزء.

بالطبع, هذا لا يزال يستخدم المفرد:على ThreadLocal.ولكن الفعلي الفول لا تحتاج إلى أن تكون أكثر.يمكن حتى يكون الطلب-راقب, و هذا الحل يعمل أيضا إذا كان لديك العديد من الحروب في التطبيق مع libaries في الأذن.لا يزال, قد تفكر في استخدام هذه ThreadLocal بسوء استخدام عادي ووحدانية.;-)

ربما الربيع يوفر بالفعل مماثل الحل ؟ لم أجد واحد, ولكن أنا لا أعرف على وجه اليقين.

SpringApplicationContext.java

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

/**
 * Wrapper to always return a reference to the Spring Application 
Context from
 * within non-Spring enabled beans. Unlike Spring MVC's 
WebApplicationContextUtils
 * we do not need a reference to the Servlet context for this. All we need is
 * for this bean to be initialized during application startup.
 */
public class SpringApplicationContext implements 
ApplicationContextAware {

  private static ApplicationContext CONTEXT;

  /**
   * This method is called from within the ApplicationContext once it is 
   * done starting up, it will stick a reference to itself into this bean.
  * @param context a reference to the ApplicationContext.
  */
  public void setApplicationContext(ApplicationContext context) throws BeansException {
    CONTEXT = context;
  }

  /**
   * This is about the same as context.getBean("beanName"), except it has its
   * own static handle to the Spring context, so calling this method statically
   * will give access to the beans by name in the Spring application context.
   * As in the context.getBean("beanName") call, the caller must cast to the
   * appropriate target class. If the bean does not exist, then a Runtime error
   * will be thrown.
   * @param beanName the name of the bean to get.
   * @return an Object reference to the named bean.
   */
  public static Object getBean(String beanName) {
    return CONTEXT.getBean(beanName);
  }
}

المصدر: http://sujitpal.blogspot.de/2007/03/accessing-spring-beans-from-legacy-code.html

نلقي نظرة على ContextSingletonBeanFactoryLocator.فإنه يوفر ثابت accessors للحصول على عقد من الربيع السياقات ، على افتراض أنها كانت مسجلة في طرق معينة.

انها ليست جميلة و أكثر تعقيدا من ربما كنت ترغب ، لكنه يعمل.

علما بأن طريق تخزين أي دولة من الحالي ApplicationContext, أو ApplicationContext نفسها في متغير ثابت - على سبيل المثال باستخدام نمط المفرد - سوف تجعل الخاصة بك الاختبارات غير مستقر ولا يمكن التنبؤ بها إذا كنت تستخدم الربيع الاختبار.لأن هذا هو الربيع-اختبار مخابئ وإعادة استعمال تطبيق السياقات في نفس JVM.على سبيل المثال:

  1. اختبار تشغيل و هو مشروح مع @ContextConfiguration({"classpath:foo.xml"}).
  2. ب اختبار تشغيل و هو مشروح مع @ContextConfiguration({"classpath:foo.xml", "classpath:bar.xml})
  3. اختبار التشغيل C و هو مشروح مع @ContextConfiguration({"classpath:foo.xml"})

عند اختبار أشواط ، ApplicationContext يتم إنشاء أي حبوب implemeting ApplicationContextAware أو autowiring ApplicationContext قد يكتب إلى متغير ثابت.

عندما الاختبار ب يعمل نفس الشيء يحدث متغير ثابت يشير الآن إلى اختبار B ApplicationContext

عند اختبار ج أشواط ، لا الفاصوليا يتم إنشاؤها كما TestContext (وهنا ApplicationContext) من اختبار resused.الآن لديك متغير ثابت مشيرا إلى أخرى ApplicationContext من واحد حاليا عقد الفول لاختبار الخاص بك.

هناك العديد من الطرق للحصول على التطبيق في سياق الربيع التطبيق.تلك هي بالنظر إلى رفع الصوت عاليا:

  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

ApplicationContextAware:

واجهة تنفذ من قبل أي كائن التي ترغب في أن يتم إعلامك من ApplicationContext أنه يعمل في.تنفيذ هذه الواجهة من المنطقي على سبيل المثال عندما كائن يتطلب الوصول إلى مجموعة من التعاون الفاصوليا.

  1. عبر Autowired:

    @Autowired
    private ApplicationContext applicationContext;
    

هنا @Autowired الكلمة سوف نقدم applicationContext.Autowired لديه بعض المشاكل.فإنه سيتم إنشاء المشكلة خلال وحدة الفحص.

ليس متأكدا من مدى فائدة هذا سوف يكون ، ولكن يمكنك أيضا الحصول على السياق عند تهيئة التطبيق.هذا هو أقرب يمكنك الحصول على السياق ، حتى قبل @Autowire.

@SpringBootApplication
public class Application extends SpringBootServletInitializer {
    private static ApplicationContext context;

    // I believe this only runs during an embedded Tomcat with `mvn spring-boot:run`. 
    // I don't believe it runs when deploying to Tomcat on AWS.
    public static void main(String[] args) {
        context = SpringApplication.run(Application.class, args);
        DataSource dataSource = context.getBean(javax.sql.DataSource.class);
        Logger.getLogger("Application").info("DATASOURCE = " + dataSource);

يرجى ملاحظة أن ؛ رمز أدناه سيتم إنشاء تطبيق جديد سياق بدلا من استخدام تحميلها بالفعل واحدة.

private static final ApplicationContext context = 
               new ClassPathXmlApplicationContext("beans.xml");

نلاحظ أيضا أن beans.xml ينبغي أن تكون جزءا من src/main/resources يعني في الحرب هو جزء من WEB_INF/classes, حيث التطبيق الحقيقي سيتم تحميلها من خلال applicationContext.xml ذكر في Web.xml.

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>META-INF/spring/applicationContext.xml</param-value>
</context-param>

فمن من الصعب ذكر applicationContext.xml المسار في ClassPathXmlApplicationContext منشئ. ClassPathXmlApplicationContext("META-INF/spring/applicationContext.xml") لن تكون قادرا على تحديد موقع الملف.

لذا فمن الأفضل استخدام القائمة applicationContext باستخدام التعليقات التوضيحية.

@Component
public class OperatorRequestHandlerFactory {

    public static ApplicationContext context;

    @Autowired
    public void setApplicationContext(ApplicationContext applicationContext) {
        context = applicationContext;
    }
}

أنا أعرف الإجابة على هذا السؤال, ولكن أود أن حصة هذه Kotlin رمز لم لاسترداد الربيع السياق.

أنا لست متخصص ، لذلك أنا فتح النقاد الآراء والنصائح:

https://gist.github.com/edpichler/9e22309a86b97dbd4cb1ffe011aa69dd

package com.company.web.spring

import com.company.jpa.spring.MyBusinessAppConfig
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.ApplicationContext
import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Import
import org.springframework.stereotype.Component
import org.springframework.web.context.ContextLoader
import org.springframework.web.context.WebApplicationContext
import org.springframework.web.context.support.WebApplicationContextUtils
import javax.servlet.http.HttpServlet

@Configuration
@Import(value = [MyBusinessAppConfig::class])
@ComponentScan(basePackageClasses  = [SpringUtils::class])
open class WebAppConfig {
}

/**
 *
 * Singleton object to create (only if necessary), return and reuse a Spring Application Context.
 *
 * When you instantiates a class by yourself, spring context does not autowire its properties, but you can wire by yourself.
 * This class helps to find a context or create a new one, so you can wire properties inside objects that are not
 * created by Spring (e.g.: Servlets, usually created by the web server).
 *
 * Sometimes a SpringContext is created inside jUnit tests, or in the application server, or just manually. Independent
 * where it was created, I recommend you to configure your spring configuration to scan this SpringUtils package, so the 'springAppContext'
 * property will be used and autowired at the SpringUtils object the start of your spring context, and you will have just one instance of spring context public available.
 *
 *Ps: Even if your spring configuration doesn't include the SpringUtils @Component, it will works tto, but it will create a second Spring Context o your application.
 */
@Component
object SpringUtils {

        var springAppContext: ApplicationContext? = null
    @Autowired
    set(value) {
        field = value
    }



    /**
     * Tries to find and reuse the Application Spring Context. If none found, creates one and save for reuse.
     * @return returns a Spring Context.
     */
    fun ctx(): ApplicationContext {
        if (springAppContext!= null) {
            println("achou")
            return springAppContext as ApplicationContext;
        }

        //springcontext not autowired. Trying to find on the thread...
        val webContext = ContextLoader.getCurrentWebApplicationContext()
        if (webContext != null) {
            springAppContext = webContext;
            println("achou no servidor")
            return springAppContext as WebApplicationContext;
        }

        println("nao achou, vai criar")
        //None spring context found. Start creating a new one...
        val applicationContext = AnnotationConfigApplicationContext ( WebAppConfig::class.java )

        //saving the context for reusing next time
        springAppContext = applicationContext
        return applicationContext
    }

    /**
     * @return a Spring context of the WebApplication.
     * @param createNewWhenNotFound when true, creates a new Spring Context to return, when no one found in the ServletContext.
     * @param httpServlet the @WebServlet.
     */
    fun ctx(httpServlet: HttpServlet, createNewWhenNotFound: Boolean): ApplicationContext {
        try {
            val webContext = WebApplicationContextUtils.findWebApplicationContext(httpServlet.servletContext)
            if (webContext != null) {
                return webContext
            }
            if (createNewWhenNotFound) {
                //creates a new one
                return ctx()
            } else {
                throw NullPointerException("Cannot found a Spring Application Context.");
            }
        }catch (er: IllegalStateException){
            if (createNewWhenNotFound) {
                //creates a new one
                return ctx()
            }
            throw er;
        }
    }
}

الآن, الربيع السياق متاحة للجمهور ، أن تكون قادرة على استدعاء نفس طريقة مستقلة عن السياق (junit الاختبارات والفاصوليا يدويا مثيل الطبقات) مثل على هذا بريمج جافا:

@WebServlet(name = "MyWebHook", value = "/WebHook")
public class MyWebServlet extends HttpServlet {


    private MyBean byBean
            = SpringUtils.INSTANCE.ctx(this, true).getBean(MyBean.class);


    public MyWebServlet() {

    }
}

هل autowire في الربيع الفول على النحو التالي :@Autowired خاصة ApplicationContext appContext;

سوف applicationcontext الكائن.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top