← Назад к вопросам

Как создать Singleton в Spring?

2.0 Middle🔥 161 комментариев
#Spring Boot и Spring Data

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Как создать Singleton в Spring

Spring автоматически управляет жизненным циклом beans и по умолчанию создаёт их как singleton (одна единственная инстанция на весь контекст приложения). Однако это требует правильного понимания scope beans и способов создания. Рассмотрим все подходы.

1. Автоматический Singleton через @Bean и @Component

По умолчанию все beans в Spring имеют scope = singleton. Это значит, что Spring создаст одну инстанцию на весь контекст приложения.

@Component
public class DatabaseConnection {
    public DatabaseConnection() {
        System.out.println("DatabaseConnection создан");
    }
    
    public void connect() {
        System.out.println("Подключение к БД");
    }
}

@Configuration
public class AppConfig {
    @Bean
    public DatabaseConnection databaseConnection() {
        return new DatabaseConnection();
    }
}

Можно проверить, что это действительно одна и та же инстанция:

@RestController
public class TestController {
    @Autowired
    private DatabaseConnection db1;
    
    @Autowired
    private DatabaseConnection db2;
    
    @GetMapping("/test")
    public String test() {
        return db1 == db2 ? "Singleton: true" : "Singleton: false";
    }
}

2. Явное указание scope = singleton

Хотя это и дефолт, можно явно указать scope:

@Component
@Scope("singleton")
public class UserService {
}

@Configuration
public class AppConfig {
    @Bean
    @Scope("singleton")
    public UserService userService() {
        return new UserService();
    }
}

3. Singleton с инициализацией и очисткой

Часто singleton нужно инициализировать при создании и очищать при завершении:

@Component
public class DatabasePool {
    
    private List<Connection> connections = new ArrayList<>();
    
    @PostConstruct
    public void init() {
        System.out.println("Инициализация пула");
        for (int i = 0; i < 5; i++) {
            connections.add(createConnection());
        }
    }
    
    @PreDestroy
    public void cleanup() {
        System.out.println("Очистка пула");
        connections.forEach(Connection::close);
        connections.clear();
    }
    
    public Connection getConnection() {
        return connections.get(0);
    }
    
    private Connection createConnection() {
        return null;
    }
}

4. Lazy инициализация Singleton

По умолчанию singleton инициализируется при запуске приложения. Если нужна ленивая инициализация:

@Component
@Lazy
public class ExpensiveService {
    public ExpensiveService() {
        System.out.println("ExpensiveService создан");
    }
}

5. Thread-safe Singleton через synchronized

Если ты создаёшь singleton вручную (не через Spring), нужна синхронизация:

public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

Но в Spring это не нужно — контейнер сам гарантирует thread-safety!

6. Double-checked locking

Для вручную созданного singleton:

public class Singleton {
    private static volatile Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

7. Enum Singleton

Этот подход гарантирует singleton и thread-safety:

public enum Singleton {
    INSTANCE;
    
    private String name = "Singleton";
    
    public void doSomething() {
        System.out.println(name);
    }
}

Singleton.INSTANCE.doSomething();

8. Singleton как Static Factory

public class DatabaseConnection {
    private static final DatabaseConnection INSTANCE = new DatabaseConnection();
    
    private DatabaseConnection() {}
    
    public static DatabaseConnection getInstance() {
        return INSTANCE;
    }
}

9. Spring Profile-specific Singleton

Разные singleton реализации для разных окружений:

@Configuration
public class AppConfig {
    
    @Bean
    @Profile("dev")
    public DatabaseService devDatabase() {
        return new H2DatabaseService();
    }
    
    @Bean
    @Profile("prod")
    public DatabaseService prodDatabase() {
        return new PostgresDatabaseService();
    }
}

10. Nested Singleton Pattern

public class Singleton {
    private Singleton() {}
    
    private static class SingletonHolder {
        static final Singleton INSTANCE = new Singleton();
    }
    
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

Типичные ошибки

Ошибка 1: Использование new вместо Autowired

Неправильно:

public class Controller {
    private UserService userService = new UserService();
}

Правильно:

public class Controller {
    @Autowired
    private UserService userService;
}

Ошибка 2: Неправильное управление жизненным циклом

Не забывай про @PostConstruct и @PreDestroy для инициализации и очистки ресурсов.

Вывод

В Spring Singleton по умолчанию — это встроенная функция контейнера. Для простых случаев используй @Component или @Bean. Для сложной логики — добавь @PostConstruct/@PreDestroy. Spring гарантирует thread-safety автоматически, поэтому синхронизация не требуется.