Что нужно сделать с методом класса с аннотацией Bean, чтобы Spring его увидел?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Использование аннотации @Bean в Spring
@Bean — это аннотация в Spring Framework, которая указывает, что метод производит bean, управляемый контейнером Spring. Однако для того чтобы Spring увидел и зарегистрировал этот bean, необходимо выполнить несколько требований.
Основное требование: @Configuration класс
Метод с аннотацией @Bean должен находиться внутри класса, помеченного аннотацией @Configuration.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
// Spring обнаружит и зарегистрирует этот bean
@Bean
public UserService userService() {
return new UserService();
}
@Bean
public UserRepository userRepository() {
return new UserRepository();
}
}
Почему нужен @Configuration?
Класс с аннотацией @Configuration служит источником определений bean для Spring. Spring сканирует такие классы и вызывает методы, помеченные @Bean, чтобы получить instances бинов.
Сканирование компонентов
Spring должен обнаружить сам класс @Configuration. Для этого нужно:
- Использовать @ComponentScan — явно указать пакеты для сканирования
@Configuration
@ComponentScan(basePackages = {"com.example.config", "com.example.service"})
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
}
- Или положить класс в базовый пакет приложения
// com.example.Application - main класс
@SpringBootApplication // включает @ComponentScan на текущий пакет
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// com.example.config.AppConfig - будет обнаружен автоматически
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
}
Зависимости между beans
Для использования других бинов в методе @Bean нужно передать их как параметры:
@Configuration
public class AppConfig {
@Bean
public UserRepository userRepository() {
return new UserRepository();
}
// Spring автоматически внедрит userRepository
@Bean
public UserService userService(UserRepository userRepository) {
return new UserService(userRepository);
}
// Можно внедрять несколько зависимостей
@Bean
public UserController userController(
UserService userService,
UserRepository userRepository) {
return new UserController(userService, userRepository);
}
}
Именование бинов
По умолчанию имя бина совпадает с именем метода. Можно изменить через параметр name:
@Configuration
public class AppConfig {
@Bean(name = "customUserService")
public UserService userService() {
return new UserService();
}
// Несколько имён для одного бина
@Bean(name = {"userService", "mainService"})
public UserService getUserService() {
return new UserService();
}
}
// Использование бина по имени
@Service
public class OrderService {
@Autowired
@Qualifier("customUserService")
private UserService userService;
}
Scope бинов
По умолчанию бины имеют scope singleton (один экземпляр на приложение). Можно изменить через @Scope:
@Configuration
public class AppConfig {
// Singleton - по умолчанию
@Bean
public UserService singletonService() {
return new UserService();
}
// Prototype - новый экземпляр каждый раз
@Bean
@Scope("prototype")
public UserContext userContext() {
return new UserContext();
}
// Request scope - новый для каждого HTTP запроса
@Bean
@Scope("request")
public RequestData requestData() {
return new RequestData();
}
}
Условная регистрация бинов
@Configuration
public class AppConfig {
// Бин регистрируется только если свойство true
@Bean
@ConditionalOnProperty(name = "feature.enabled", havingValue = "true")
public FeatureService featureService() {
return new FeatureService();
}
// Бин регистрируется только если класса нет в classpath
@Bean
@ConditionalOnMissingBean(EmailService.class)
public EmailService defaultEmailService() {
return new DefaultEmailService();
}
// Бин регистрируется только если другой бин существует
@Bean
@ConditionalOnBean(UserRepository.class)
public UserService userService(UserRepository userRepository) {
return new UserService(userRepository);
}
}
Инициализация и уничтожение
@Configuration
public class AppConfig {
@Bean
public UserService userService() {
return new UserService();
}
// Методы инициализации и уничтожения
@Bean(initMethod = "init", destroyMethod = "cleanup")
public Database database() {
return new Database();
}
}
public class Database {
public void init() {
System.out.println("Database initialized");
}
public void cleanup() {
System.out.println("Database cleanup");
}
}
// Или через PostConstruct / PreDestroy
public class DatabaseV2 {
@PostConstruct
public void init() {
System.out.println("Database initialized");
}
@PreDestroy
public void cleanup() {
System.out.println("Database cleanup");
}
}
Примеры реальных конфигураций
@Configuration
public class DataSourceConfig {
// Конфигурация DataSource
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:postgresql://localhost:5432/mydb");
config.setUsername("user");
config.setPassword("password");
config.setMaximumPoolSize(10);
return new HikariDataSource(config);
}
// Конфигурация JdbcTemplate
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
// Конфигурация RestTemplate
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf().disable()
.authorizeRequests()
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.build();
}
}
Лучшие практики
-
Используйте @Configuration для создания бинов
- Это явно указывает, что класс содержит определения бинов
-
Передавайте зависимости через параметры метода
- Spring автоматически разрешит их
-
Используйте значимые имена методов
- Это станет именем бина по умолчанию
-
Разделяйте конфигурацию по темам
- Один класс для database конфигурации, другой для security
-
Используйте условную регистрацию
- @ConditionalOnProperty, @ConditionalOnBean для гибкости
-
Явно указывайте scope для non-singleton бинов
- Это предотвращает неожиданное поведение
При правильной конфигурации Spring легко обнаружит и зарегистрирует все ваши бины.