简体   繁体   English

如何将Spring bean注入Exception

[英]How to inject Spring bean into Exception

I found similar question here Spring - how to inject a bean into class which is created many times at runtime? 我在Spring中发现了类似的问题- 如何将bean注入到在运行时多次创建的类中? and Why is Spring's ApplicationContext.getBean considered bad? 为什么Spring的ApplicationContext.getBean被认为是坏的? but neither really answers my case. 但两个都没有真正回答我的情况

Example code: 示例代码:

public interface AppNameProvider
{
    String getAppName();
}

public class DefaultAppNameProvider implements AppNameProvider
{
    private String appName;

    public String getAppName()
    {
        return appName;
    }

    public setAppName(String appName)
    {
        this.appName = appName;
    }
}

<bean id="appNameProvider" class="some.package.DefaultAppNameProvider">
    <property name="appName" value="MyApplication"/>
</bean> 

public class MyException extends RuntimeException
{
    // Imagine obligatory constructors here...

    public String getAppName()
    {
        // Inject appNameProvider somehow here
        return appNameProvider.getAppName();
    }
}

I have a provider bean declared in xml. 我有一个在xml中声明的提供者bean。 In the example the value is simply declared in xml for simplicity. 在示例中,为简单起见,该值仅在xml中声明。 I have a custom exception which needs to receive something from a bean. 我有一个自定义异常,需要从bean接收一些东西。 How to inject such bean into the exception class. 如何将这样的bean注入异常类。 I obviously can't declare exception as a Spring bean. 我显然不能将异常声明为Spring bean。 The appName is just a simple example, it can be anything else. appName只是一个简单的例子,它可以是其他任何东西。 You might wonder why a hypothetic caller of myException.getAppName() wouldn't just simply call appNameProvider.getAppName()? 您可能想知道为什么myException.getAppName()的假设调用者不只是简单地调用appNameProvider.getAppName()? Because it's not intended so, eg there might be different provider in each exception etc. 因为它不是这样的,例如每个例外中可能有不同的提供者等。

I would like to know how to inject the bean into such exception. 我想知道如何将bean注入此类异常。 I can add setter and set the provider at the exception throw time. 我可以添加setter并在异常抛出时设置提供程序。 But I have to know which provider to use from outside (in my app code) and I would have to do it redundantly everywhere where I want to throw this exception. 但我必须知道从外部使用哪个提供程序(在我的应用程序代码中),我将不得不在我想要抛出此异常的任何地方冗余地执行此操作。 Ideally I would like to declare which provider to use for the exception in the xml. 理想情况下,我想声明哪个提供程序用于xml中的异常。

Ultimately the question can be widened so that instead of exception we think of any runtime object which is not a bean itself. 最终,问题可以扩大,以便我们可以考虑任何不是bean本身的运行时对象,而不是异常。

PS I'm not scared of having hardcoded dependencies to Spring in the code. PS我不害怕在代码中对Spring进行硬编码依赖。 I use Spring and I want to embrace it - not avoid it. 我使用Spring,我想拥抱它 - 不要避免它。

  1. Inject the provider in the class which throws the exception 在抛出异常的类中注入提供程序
  2. Provide a constructor/setter by which to set the provider to the exception 提供构造函数/ setter,通过该构造函数/ setter将提供程序设置为异常
  3. throw new MyException(provider)

It's a while since I've done it, but if you are using / can use annotation based config and aspectJ you can annotate a class as @Configurable which will allow you get Spring to inject dependencies each time an instance of the class is created. 我已经做了一段时间了,但是如果你正在使用/可以使用基于注释的配置和aspectJ,你可以将一个类注释为@Configurable ,这将允许你在每次创建一个类的实例时让Spring注入依赖项。

http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html#aop-atconfigurable http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html#aop-atconfigurable

You can create a component and inject the property in it. 您可以创建一个组件并在其中注入该属性。 For example you can define DefaultAppNameProvider as a component and thus you can autowire other components in it. 例如,您可以将DefaultAppNameProvider定义为组件,因此您可以在其中自动装配其他组件。 You can then provide using a singleton design pattern with a private constructor a static method called getInstance. 然后,您可以使用单一设计模式和私有构造函数提供一个名为getInstance的静态方法。 In the class MyException you can access the DefaultAppNameProvider property using DefaultAppNameProvider.getInstance().getAppName() . 在类MyException您可以使用DefaultAppNameProvider.getInstance().getAppName()访问DefaultAppNameProvider属性。

Example code for the singleton component. 单例组件的示例代码。

@Component
public class DefaultAppNameProvider {
    private static DefaultAppNameProvider instance;

    private DefaultAppNameProvider() {
        instance = this;
    }

    public static DefaultAppNameProvider getInstance() {
       return instance;
    }

    private String appName;

    public String getAppName()
    {
        return appName;
    }

    public setAppName(String appName)
    {
        this.appName = appName;
    }
}

I have been looking around in the mean time. 我一直在环顾四周。 I found this . 我找到了这个 In the end I used the following solution. 最后我使用了以下解决方案。

According to 1 created an ApplicationContextProvider: 根据1创建的ApplicationContextProvider:

public class ApplicationContextProvider implements ApplicationContextAware
{
    private static ApplicationContext applicationContext;

    public static ApplicationContext getApplicationContext()
    {
        return applicationContext;
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
    {
        ApplicationContextProvider.applicationContext = applicationContext;
    }
}

Then AppNameProviderFactory which maps providers to the keys. 然后AppNameProviderFactory将提供者映射到键。 Key can be exception name: 键可以是例外名称:

public class AppNameProviderFactory
{
    private Map<String,AppNameProvider> map;

    public void setMap(Map<String, AppNameProvider> map)
    {
        this.map = map;
    }

    public AppNameProvider getAppNameProvider(String key)
    {
        return map.get(key);
    }
}

And in xml I define the mappings: 在xml中我定义了映射:

<bean id="appNameProviderFactory" class="some.domain.AppNameProviderFactory">
    <property name="map">
        <map>
            <entry key="MyException" value-ref="appNameProvider"/>
        </map>
    </property>
</bean>

And finally in the exception class: 最后在异常类中:

public class MyException extends RuntimeException
{
    // Imagine obligatory constructors here...

    public String getAppName()
    {
        final ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();
        AppNameProviderFactory factory = (AppNameProviderFactory) applicationContext.getBean("appNameProviderFactory");
        return factory.getAppNameProvider("MyException").getAppName();
    }
}

This way I have configuration in xml, decoupled from business code. 这样我就可以在xml中进行配置,与业务代码分离。 I can have as many exceptions with different providers as needed. 我可以根据需要为不同的提供商提供尽可能多的例外。

Thanks all for suggestions. 谢谢大家的建议。 PS Error handling and NPE handling ommited for simplicity. PS错误处理和NPE处理由于简单而无法理解。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM