Как ввести боб Spring в исключение - PullRequest
4 голосов
/ 24 ноября 2011

Я нашел похожий вопрос здесь Spring - как внедрить bean-компонент в класс, который создается много раз во время выполнения? и Почему SpringCon 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. В примере значение просто объявлено в xml для простоты. У меня есть пользовательское исключение, которое должно получить что-то из бобов. Как внедрить такой боб в класс исключений. Я, очевидно, не могу объявить исключение как бин Spring. AppName - простой пример, это может быть что угодно. Вы можете спросить, почему гипотетический вызывающий объект myException.getAppName () не просто вызовет appNameProvider.getAppName ()? Потому что это не так, например в каждом исключении могут быть разные провайдеры и т. д.

Я хотел бы знать, как ввести боб в такое исключение. Я могу добавить сеттер и установить провайдера во время исключения. Но я должен знать, какого провайдера использовать извне (в коде моего приложения), и мне придется делать это излишне везде, где я хочу вызвать это исключение. В идеале я хотел бы объявить, какой поставщик использовать для исключения в xml.

В конечном итоге вопрос можно расширить, чтобы вместо исключения мы думали о любом объекте времени выполнения, который не является самим компонентом.

PS Я не боюсь иметь жестко закодированные зависимости от Spring в коде. Я использую Spring и хочу принять это, а не избегать.

Ответы [ 4 ]

1 голос
/ 24 ноября 2011
  1. Внедрить провайдера в класс, который выдает исключение
  2. Предоставить конструктор / установщик, с помощью которого поставщик может установить исключение
  3. throw new MyException(provider)
0 голосов
/ 25 ноября 2011

Я тем временем осматривался. Я нашел это . В итоге я использовал следующее решение.

Согласно 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 опущены для простоты.

0 голосов
/ 24 ноября 2011

Вы можете создать компонент и добавить в него свойство.Например, вы можете определить DefaultAppNameProvider как компонент и, таким образом, вы можете автоматически связать другие компоненты в нем.Затем вы можете предоставить с помощью одноэлементного шаблона проектирования с закрытым конструктором статический метод getInstance.В классе MyException вы можете получить доступ к свойству DefaultAppNameProvider, используя DefaultAppNameProvider.getInstance().getAppName().

Пример кода для одноэлементного компонента.

@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 голосов
/ 24 ноября 2011

Я уже давно это сделал, но если вы используете / можете использовать конфигурацию на основе аннотаций и aspectJ, вы можете аннотировать класс как @Configurable, что позволит вам заставить Spring вставлять зависимости каждый раз, когда экземпляр класс создан.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...