如何将Spring Bean注入到异常中

4
我在这里找到了类似的问题:Spring - 如何将bean注入到在运行时创建多次的类中?为什么Spring的ApplicationContext.getBean被认为是不好的?,但都没有真正回答我的问题。
示例代码:
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并希望拥抱它-而不是避免它。

你能否发布一下抛出 MyException 新实例的代码?我想知道是否可以通过构造函数传递一个 AppNameProvider 的引用... - JBert
4个回答

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

我可以添加setter并在异常抛出时设置提供程序。但是,我必须从外部(在我的应用程序代码中)知道要使用哪个提供程序,并且我必须在每个想要抛出此异常的地方都做冗余的工作。 - user1063845
@user1063845,问题是我想知道你在什么情况下会抛出异常,以及为什么你需要在捕获异常的地方使用AppnameProvider。我期望当你抛出异常时,某人在实现AppnameProvider的类上执行了错误操作,这意味着你__有__提供程序的实例。我相信Spring可以做一些魔法,但对我来说,这听起来像是你试图修复设计中的缺陷。你需要使用Spring的魔法才能使代码正常工作,这可能会使任何后来处理代码的人难以理解。 - JBert

0

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

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处理被省略了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接