2011-11-24 128 views
4

我在这里发现了类似的问题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声明提供商豆。在这个例子中,为了简单起见,在xml中简单地声明了该值。我有一个自定义的异常,需要从bean中接收一些东西。如何将这样的bean注入到异常类中。我显然不能将异常声明为Spring bean。 appName只是一个简单的例子,它可以是其他任何东西。您可能想知道为什么myException.getAppName()的假设调用者不会仅仅调用appNameProvider.getAppName()?因为它并非如此,例如在每个异常中可能会有不同的提供者等。

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

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

PS我不害怕在代码中有Spring的硬编码依赖关系。我使用Spring,我想拥抱它 - 不是避免它。

+0

你能发布抛出一个'MyException'的新实例的代码吗?我不知道你是否无法通过构造函数传递给AppNameProvider的引用... – JBert

回答

1
  1. 注入其中抛出异常
  2. 提供了被利用到提供者设置为异常的构造函数/ setter方法的类提供
  3. throw new MyException(provider)
+0

Bozho和JBert的答案: 我可以添加setter并在异常抛出时设置提供程序。但是我必须知道从外部使用哪个提供程序(在我的应用程序代码中),并且我必须在要引发此异常的任何地方冗余地执行此操作。 – user1063845

+0

@ user1063845事情是,我想知道在什么情况下你会抛出异常,为什么你实际上需要在你捕获它的地方的AppnameProvider。我期望当你抛出一个异常时,有人在实现AppnameProvider的类上做了错误的操作,这意味着你有__拥有提供者的实例。我相信Spring可以做一些魔术技巧,但是为了达到它,听起来就像你试图修复你设计中的一个缺陷。你需要做这项工作的Spring魔法可能会让代码难以理解,任何后来在代码上工作的人都会觉得难以理解。 – JBert

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处理已被忽略。