Подтвердить что ты не робот

Правильный способ создания синглета a Spring bean

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

Преимущество в том, что контекст Spring не загружается должным образом, заключается в том, что люди будут замечать и исправлять конфигурацию во время развертывания. В отличие от использования 'non spring bean' singleton: когда это генерирует исключение во время инициализации, никто не замечает.. пока фактический пользователь не пожалуется на недостающие функциональные возможности.

Мои изменения работают так, как ожидалось. но я не уверен, что я поступаю правильно.
Любые мысли?

Код выглядит следующим образом:

public class MySingleton {

    private static MySingleton INSTANCE = null;
    private MySingleton(){}


public static MySingleton getInstance(){
    if(INSTANCE == null){
        synchronized(MySingleton.class){
            if(INSTANCE == null){
                try{
                    doWork()
                }catch(Exception e){
                    throw new IllegalStateException("xyz", e);
                }
                INSTANCE = new MySingleton();
            }
        }
    }

    return INSTANCE;
}

private static void doWork() {
    // do some work
    }

}

И в Spring config xml, bean будет определен как:

<bean id="MySingletonBean"
    class="com.MySingleton"
    factory-method="getInstance" lazy-init="false" singleton="true">
</bean>

Примечание: Большинство из них аналогично стратегии, обсуждаемой в этой статье: http://springtips.blogspot.com/2007/06/configuration-hell-remedy-with.html


Изменить 1:

Классы, которые используют этот синглтон, не сами Spring beans.. они просто не-w763 > pojos, что я не могу преобразовать в spring. Они должны полагаться на метод getInstance(), чтобы получить синглтон.


Изменить 2: (копирование комментария, сделанного ниже в этом разделе описания)  Я пытаюсь настроить две вещи:

  • Я хочу, чтобы Spring инициализировал синглтон. Так что если инициализация завершается неудачей, загрузка приложения не выполняется.
  • Я хочу, чтобы другие классы могли использовать классы, не полагаясь на contextAwareObj.getBean( "MySingleton" )


РЕДАКТИРОВАТЬ 3 (ОКОНЧАТЕЛЬНЫЙ): Я решил сделать этот класс синглом... и не делаю его Spring bean. Если он не будет инициализирован, он будет записывать что-то в файл журнала. Мы надеемся, что человек, выполняющий развертывание, заметит... Я отказался от подхода, о котором я упоминал ранее, потому что я чувствую, что в будущем он создаст кошмар для обслуживания, поэтому мне пришлось выберите между - singleton - или - Spring bean. Я выбрал синглтон.
4b9b3361

Ответ 1

Вы должны объявить поле INSTANCE как volatile для корректной работы блокировки с двойным проверкой.

См. Эффективная Java, Пункт 71.

Ответ 2

Почему вы используете одноэлементный шаблон на первом месте? Просто позвольте Spring создать bean для вас (с областью по умолчанию singleton) и... использовать его. Конечно, всегда кто-то может создать bean вручную, но это никогда не было проблемой в моем случае.

Включение зависимостей и Spring -установленный bean жизненный цикл значительно облегчат вашу жизнь (просто посмотрите, сколько ошибок вы можете избежать). Также обратите внимание, что исключения, отбрасываемые из метода c-tor или @PostContruct, будут распространяться и также запускать запуск контекста приложения.

ОБНОВЛЕНИЕ. Я понимаю вашу точку зрения. Вот что мне пришло в голову:

@Service
public class Singleton {

    private static AtomicReference<Singleton> INSTANCE = new AtomicReference<Singleton>();

    public Singleton() {
        final Singleton previous = INSTANCE.getAndSet(this);
        if(previous != null)
            throw new IllegalStateException("Second singleton " + this + " created after " + previous);
    }

    public static Singleton getInstance() {
        return INSTANCE.get();
    }

}

И пусть Spring выполнит свою работу. Вы можете использовать DI, когда это возможно, и Singleton.getInstance(), где вам нужно.

Кроме того, существуют более жесткие решения, такие как компиляция AspectJ и впрыскивание Spring beans в основном ко всему.

Ответ 3

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

Связанная статья не имеет для меня никакого смысла, так как нет НИКАКОЙ инъекции, которую я вижу: "AnyService" вызывает метод singleton factory; что singleton ссылается в контексте приложения, не имеет значения до тех пор, пока он не ссылается, и, похоже, никакой другой bean не ссылается на него.

Ответ 4

True singleton трудно работать.

Неустойчивая блокировка с двойной проверкой также не работает. Читайте об этом на wiki http://en.wikipedia.org/wiki/Double-checked_locking

Лучше всего просто сделать это

public class MySingleton {

    private static MySingleton INSTANCE = new MySingleton();

То есть, если у вас нет каких-либо параметров конструктора в вашем реальном коде.

Ответ 5

По моему мнению, это решение для ремней и подтяжек.

Если вы создаете bean и объявляете его как одноэлемент в конфигурации, тогда не нужно защищать bean от того, чтобы его было многократно создано.

Теперь вы в основном защищаете себя от кого-то, неправильно настроив bean.

Я лично "решаю", что по документации в конфигурации spring и Javadoc.

Ответ 6

Для запуска кода при запуске (и сбое при ошибке) используйте один из многих способов регистрации событий запуска, например. см. http://www.baeldung.com/running-setup-logic-on-startup-in-spring

Пример:

@Component
public class InitializingBeanExampleBean implements InitializingBean {

    private static final Logger LOG = Logger.getLogger(InitializingBeanExampleBean.class);

    @Autowired
    private Environment environment;

    @Override
    public void afterPropertiesSet() throws Exception {
        LOG.info(Arrays.asList(environment.getDefaultProfiles()));
    }
}