@Bean
@Bean – это аннотация уровня метода и прямой аналог элемента на XML. Аннотация поддерживает некоторые атрибуты, предлагаемые , такие как:
Вы можете использовать аннотацию @Bean в классе с аннотацией @Configuration или в классе с аннотацией @Component .
Объявление бина
Чтобы объявить бин, можно аннотировать метод с помощью @Bean . Этот метод используется для регистрации определения бина в ApplicationContext того типа, который задан в качестве возвращаемого значения метода. По умолчанию имя бина совпадает с именем метода. В следующем примере показано объявление метода с аннотацией @Bean :
@Configuration public class AppConfig < @Bean public TransferServiceImpl transferService() < return new TransferServiceImpl(); >>
@Configuration class AppConfig
Предшествующая конфигурация в точности эквивалентна следующей на основе XML в Spring:
Оба объявления делают бин с именем transferService доступным в ApplicationContext , привязанном к экземпляру объекта типа TransferServiceImpl , как показано на следующем текстовом изображении:
transferService -> com.acme.TransferServiceImpl
Также можно использовать методы по умолчанию для определения бинов. Это позволяет создавать конфигурации бинов путем реализации интерфейсов с определениями бинов в методах по умолчанию.
public interface BaseConfig < @Bean default TransferServiceImpl transferService() < return new TransferServiceImpl(); >> @Configuration public class AppConfig implements BaseConfig
Можно также объявить свой метод, аннотированный @Bean , с помощью возвращаемого типа интерфейса (или базового класса), как показано в следующем примере:
@Configuration public class AppConfig < @Bean public TransferService transferService() < return new TransferServiceImpl(); >>
@Configuration class AppConfig < @Bean fun transferService(): TransferService < return TransferServiceImpl() >>
Однако это ограничивает видимость для прогнозирования расширенного типа указанным типом интерфейса (TransferService ). Затем, когда полный тип (TransferServiceImpl ) единожды распознается контейнером, создается экземпляр затронутого бина-одиночки. Экземпляры бинов-одиночек без отложенной инициализации создаются в соответствии с порядком их объявления, поэтому вы можете заметить разные результаты согласования по типам в зависимости от того, когда другой компонент пытается выполнить согласование по необъявленному типу (например, @Autowired TransferServiceImpl , который разрешается только после создания экземпляра бина transferService ).
Если вы постоянно ссылаетесь на свои типы по объявленному интерфейсу службы, то ваши возвращаемые типы, помеченные аннотацией @Bean , могут без проблем следовать этому проектному решению. Однако для компонентов, реализующих несколько интерфейсов, или для компонентов, на которые потенциально можно ссылаться по их типу реализации, безопаснее объявить максимально конкретный возвращаемый тип (по крайней мере, настолько конкретный, насколько этого требуют точки внедрения, ссылающиеся на ваш бин).
Зависимости бинов
Метод, аннотированный @Bean , может иметь произвольное количество параметров, которые описывают зависимости, необходимые для создания этого бина. Например, если нашему TransferService требуется AccountRepository , мы можем осуществить эту зависимость с помощью параметра метода, как показано в следующем примере:
@Configuration public class AppConfig < @Bean public TransferService transferService(AccountRepository accountRepository) < return new TransferServiceImpl(accountRepository); >>
Annotation Interface Bean
The names and semantics of the attributes to this annotation are intentionally similar to those of the element in the Spring XML schema. For example:
@Bean public MyBean myBean() < // instantiate and configure MyBean obj return obj; >
Bean Names
While a name() attribute is available, the default strategy for determining the name of a bean is to use the name of the @Bean method. This is convenient and intuitive, but if explicit naming is desired, the name attribute (or its alias value ) may be used. Also note that name accepts an array of Strings, allowing for multiple names (i.e. a primary bean name plus one or more aliases) for a single bean.
@Bean() // bean available as 'b1' and 'b2', but not 'myBean' public MyBean myBean() < // instantiate and configure MyBean obj return obj; >
Profile, Scope, Lazy, DependsOn, Primary, Order
Note that the @Bean annotation does not provide attributes for profile, scope, lazy, depends-on or primary. Rather, it should be used in conjunction with @Scope , @Lazy , @DependsOn and @Primary annotations to declare those semantics. For example:
@Bean @Profile("production") @Scope("prototype") public MyBean myBean() < // instantiate and configure MyBean obj return obj; >
The semantics of the above-mentioned annotations match their use at the component class level: @Profile allows for selective inclusion of certain beans. @Scope changes the bean’s scope from singleton to the specified scope. @Lazy only has an actual effect in case of the default singleton scope. @DependsOn enforces the creation of specific other beans before this bean will be created, in addition to any dependencies that the bean expressed through direct references, which is typically helpful for singleton startup. @Primary is a mechanism to resolve ambiguity at the injection point level if a single target component needs to be injected but several beans match by type.
Additionally, @Bean methods may also declare qualifier annotations and @Order values, to be taken into account during injection point resolution just like corresponding annotations on the corresponding component classes but potentially being very individual per bean definition (in case of multiple definitions with the same bean class). Qualifiers narrow the set of candidates after the initial type match; order values determine the order of resolved elements in case of collection injection points (with several target beans matching by type and qualifier).
NOTE: @Order values may influence priorities at injection points, but please be aware that they do not influence singleton startup order which is an orthogonal concern determined by dependency relationships and @DependsOn declarations as mentioned above. Also, Priority is not available at this level since it cannot be declared on methods; its semantics can be modeled through @Order values in combination with @Primary on a single bean per type.
@Bean Methods in @Configuration Classes
Typically, @Bean methods are declared within @Configuration classes. In this case, bean methods may reference other @Bean methods in the same class by calling them directly. This ensures that references between beans are strongly typed and navigable. Such so-called ‘inter-bean references’ are guaranteed to respect scoping and AOP semantics, just like getBean() lookups would. These are the semantics known from the original ‘Spring JavaConfig’ project which require CGLIB subclassing of each such configuration class at runtime. As a consequence, @Configuration classes and their factory methods must not be marked as final or private in this mode. For example:
@Configuration public class AppConfig < @Bean public FooService fooService() < return new FooService(fooRepository()); >@Bean public FooRepository fooRepository() < return new JdbcFooRepository(dataSource()); >// . >
@Bean Lite Mode
@Bean methods may also be declared within classes that are not annotated with @Configuration . For example, bean methods may be declared in a @Component class or even in a plain old class. In such cases, a @Bean method will get processed in a so-called ‘lite’ mode.
Bean methods in lite mode will be treated as plain factory methods by the container (similar to factory-method declarations in XML), with scoping and lifecycle callbacks properly applied. The containing class remains unmodified in this case, and there are no unusual constraints for the containing class or the factory methods.
In contrast to the semantics for bean methods in @Configuration classes, ‘inter-bean references’ are not supported in lite mode. Instead, when one @Bean -method invokes another @Bean -method in lite mode, the invocation is a standard Java method invocation; Spring does not intercept the invocation via a CGLIB proxy. This is analogous to inter- @Transactional method calls where in proxy mode, Spring does not intercept the invocation — Spring does so only in AspectJ mode.
@Component public class Calculator < public int sum(int a, int b) < return a+b; >@Bean public MyBean myBean() < return new MyBean(); >>
Bootstrapping
See the @ Configuration javadoc for further details including how to bootstrap the container using AnnotationConfigApplicationContext and friends.
BeanFactoryPostProcessor -returning @Bean methods
Special consideration must be taken for @Bean methods that return Spring BeanFactoryPostProcessor ( BFPP ) types. Because BFPP objects must be instantiated very early in the container lifecycle, they can interfere with processing of annotations such as @Autowired , @Value , and @PostConstruct within @Configuration classes. To avoid these lifecycle issues, mark BFPP -returning @Bean methods as static . For example:
@Bean public static PropertySourcesPlaceholderConfigurer pspc() < // instantiate, configure and return pspc . >
By marking this method as static , it can be invoked without causing instantiation of its declaring @Configuration class, thus avoiding the above-mentioned lifecycle conflicts. Note however that static @Bean methods will not be enhanced for scoping and AOP semantics as mentioned above. This works out in BFPP cases, as they are not typically referenced by other @Bean methods. As a reminder, an INFO-level log message will be issued for any non-static @Bean methods having a return type assignable to BeanFactoryPostProcessor .