如何将Spring bean注入Exception

时间:2011-11-24 13:19:32

标签: java spring dependency-injection

我在Spring - how to inject a bean into class which is created many times at runtime?Why is Spring's ApplicationContext.getBean considered bad?找到了类似的问题但是我的情况并没有真正回答。

示例代码:

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();
    }
}

我有一个在xml中声明的提供者bean。在示例中,为简单起见,该值仅在xml中声明。我有一个自定义异常,需要从bean接收一些东西。如何将这样的bean注入异常类。我显然不能将异常声明为Spring bean。 appName只是一个简单的例子,它可以是其他任何东西。您可能想知道为什么myException.getAppName()的假设调用者不只是简单地调用appNameProvider.getAppName()?因为它不是这样的,例如,每个例外都可能有不同的提供者等。

我想知道如何将bean注入此类异常。我可以添加setter并在异常抛出时设置提供程序。但我必须知道从外部使用哪个提供程序(在我的应用程序代码中),我将不得不在我想要抛出此异常的任何地方冗余地执行此操作。理想情况下,我想在xml中声明要用于异常的提供程序。

最终问题可以扩大,以便我们不考虑异常,而是考虑任何不是bean本身的运行时对象。

PS我并不害怕在代码中对Spring进行硬编码依赖。我使用Spring,我想拥抱它 - 不要避免它。

4 个答案:

答案 0 :(得分:1)

  1. 在抛出异常的类中注入提供程序
  2. 提供构造函数/ setter,通过该构造函数/ setter将提供程序设置为异常
  3. throw new MyException(provider)

答案 1 :(得分:0)

我已经有一段时间了,但如果您正在使用/可以使用基于注释的配置和aspectJ,您可以将类注释为@Configurable,这将允许您在每次实例时让Spring注入依赖项该类的创建。

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

答案 2 :(得分:0)

您可以创建一个组件并在其中注入属性。例如,您可以将DefaultAppNameProvider定义为组件,因此您可以在其中自动装配其他组件。然后,您可以使用单一设计模式和私有构造函数提供一个名为getInstance的静态方法。在类MyException中,您可以使用DefaultAppNameProvider.getInstance().getAppName()访问DefaultAppNameProvider属性。

单例组件的示例代码。

@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;
    }
}

答案 3 :(得分:0)

我一直在环顾四周。我找到了this。最后我使用了以下解决方案。

根据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;
    }
}

然后AppNameProviderFactory将提供者映射到键。密钥可以是例外名称:

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);
    }
}

在xml中我定义了映射:

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

最后在异常类中:

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();
    }
}

这样我就可以在xml中进行配置,与业务代码分离。我可以根据需要为不同的提供商提供尽可能多的例外。

感谢大家的建议。 PS错误处理和NPE处理因为简单而无法理解。