Using @DependsOn to pre initialize dependent beans first to avoid some side effects. These dependent beans are not directly injected in this bean but are still needed to be initialize first to avoid some side effect e.g. in publisher/listener pattern the dependent listeners bean might miss some events publish by this event publisher bean.
@Configuration
@ComponentScan("com.logicbig.example")
public class AppConfig {
@Bean
@DependsOn("eventListenerBean")
public EventPublisher eventPublisherBean() {
return new EventPublisher();
}
@Bean
public EventListener eventListenerBean() {
return new EventListener();
}
@Bean
public EventManager eventManagerBean() {
return new EventManager();
}
public static void main(String... strings) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
context.close();
}
}
Original PostUsing bean name to avoid ambiguity.
@Configuration
public class AppRunner {
@Bean(name = "OrderServiceA")
public OrderService orderServiceByProvider1() {
return new OrderServiceImpl1();
}
@Bean(name = "OrderServiceB")
public OrderService orderServiceByProvider2() {
return new OrderServiceImpl2();
}
@Bean
public OrderServiceClient createClient() {
return new OrderServiceClient();
}
public static void main(String... strings) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppRunner.class);
OrderServiceClient bean = context.getBean(OrderServiceClient.class);
bean.showPendingOrderDetails();
}
}
Original PostUsing @Scope on a configuration method. This annotation specifies the scope name to be used by the container. Depending on the scope, Spring creates new bean or uses cached bean every time it's accessed by the client. On Spring core framework level, the scope can be singleton or It could be prototype.
Scope valid constants.
@Configuration
public class Config {
@Bean
public UserRegistrationValidator validator () {
return new UserRegistrationValidator();
}
@Bean
public RegistrationService registrationService () {
return new RegistrationServiceImpl();
}
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean
public UserRegistrationBean userRegistrationBean () {
return new UserRegistrationBeanImpl();
}
}
Original PostThis example shows how to use Java based configuration for array injection and ordering the array using @Order annotation.
@Configuration
public class ArrayInjectOrderExample {
@Bean
public TestBean testBean () {
return new TestBean();
}
@Bean
@Order(3)
public String refString () {
return "my string 1";
}
@Bean
@Order(1)
public String refString2 () {
return "my string 2";
}
@Bean
@Order(2)
public String refString3 () {
return "my string 3";
}
public static void main (String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(
ArrayInjectOrderExample.class);
TestBean bean = context.getBean(TestBean.class);
System.out.println(Arrays.toString(bean.getStringArray()));
}
private static class TestBean {
private String[] stringArray;
@Autowired
public void setStringArray (String[] stringArray) {
this.stringArray = stringArray;
}
public String[] getStringArray () {
return stringArray;
}
}
}
Using Qualifier to avoid ambiguity.
@Configuration
public class AppRunner2 {
@Bean
@Qualifier("OrderServiceA")
public OrderService orderServiceByProvider1() {
return new OrderServiceImpl1();
}
@Bean(name = "OrderServiceB")
public OrderService orderServiceByProvider2() {
return new OrderServiceImpl2();
}
@Bean
public OrderServiceClient createClient() {
return new OrderServiceClient();
}
public static void main(String... strings) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppRunner2.class);
OrderServiceClient bean = context.getBean(OrderServiceClient.class);
bean.showPendingOrderDetails();
}
}
Original PostThese examples show the different scenarios where a @Configuration class contains @Bean methods with parameters depending on other registered bean instances.
public class BeanA {
private String name;
public BeanA(String name){
this.name = name;
}
@Override
public String toString() {
return "BeanA{" +
"name='" + name + '\'' +
'}';
}
}
public class BeanB {
private BeanA beanA;
BeanB (BeanA beanA) {
this.beanA = beanA;
}
public BeanA getBeanA () {
return beanA;
}
@Override
public String toString() {
return "BeanB{" +
"beanA=" + beanA +
'}';
}
}
public class BeanC {
private String name;
public BeanC(String name){
this.name = name;
}
@Override
public String toString() {
return "BeanC{" +
"name='" + name + '\'' +
'}';
}
}
If there's only one type registered for the target injection point parameter then the dependency is resolved by just type.
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class InjectParameterByType {
public static void main (String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(
Config.class);
BeanB beanB = context.getBean(BeanB.class);
System.out.println("In the main method: " + beanB.getBeanA());
}
@Configuration
public static class Config {
@Bean
public BeanA bean1 () {
return new BeanA("a1");
}
@Bean
public BeanB bean2 (BeanA theBean) {
BeanB beanB = new BeanB(theBean);
System.out.println("method bean2: beanB created = " + beanB +
"\n with constructor param BeanA = " + theBean);
return beanB;
}
}
}
Output
method bean2: beanB created = BeanB{beanA=BeanA{name='a1'}}
with constructor param BeanA = BeanA{name='a1'}
In the main method: BeanA{name='a1'}
In case if there are more than one bean instances of same type available then we can resolve that with bean's name. In this example the method bean1() registers the BeanA instance with name same as method's name, i.e. 'bean1' which matches the parameter name of bean3(..). Spring always matches the type first before attempting to apply some other additional strategy.
public class InjectParameterByName {
public static void main (String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(
Config.class);
BeanB beanB = context.getBean(BeanB.class);
System.out.println("In the main method: " + beanB.getBeanA());
}
@Configuration
public static class Config {
@Bean
public BeanA bean1 () {
return new BeanA("a1");
}
@Bean
public BeanA bean2 () {
return new BeanA("a2");
}
@Bean
public BeanB bean3 (BeanA bean1) {
BeanB beanB = new BeanB(bean1);
System.out.println("method bean3: beanB created = " + beanB +
"\n with constructor param BeanA: " + bean1);
return beanB;
}
}
}
Output
method bean3: beanB created = BeanB{beanA=BeanA{name='a1'}}
with constructor param BeanA: BeanA{name='a1'}
In the main method: BeanA{name='a1'}
In this example the dependency is resolve with an explicit use of @Qualifier on both sides.
public class InjectParameterByQualifier {
public static void main (String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(
Config.class);
BeanB beanB = context.getBean(BeanB.class);
System.out.println("In the main method: " + beanB.getBeanA());
}
@Configuration
public static class Config {
@Bean
public BeanA bean1 () {
return new BeanA("a1");
}
@Qualifier("myBean")
@Bean
public BeanA bean2 () {
return new BeanA("a2");
}
@Bean
public BeanB bean3 (@Qualifier("myBean") BeanA theBean) {
BeanB beanB = new BeanB(theBean);
System.out.println("method bean3: beanB created = " + beanB +
"\n with constructor param BeanA = " + theBean);
return beanB;
}
}
}
Output
method bean3: beanB created = BeanB{beanA=BeanA{name='a2'}}
with constructor param BeanA = BeanA{name='a2'}
In the main method: BeanA{name='a2'}
In this example dependency is resolved by matching bean's name of the bean's provider method with target injection point parameter's @Qualifier. Note that opposite is not possible, i.e. we cannot match a @Qualifier of provider's method with target injection point parameter's name.
public class InjectParameterByQualifier2 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(
Config.class);
BeanB beanB = context.getBean(BeanB.class);
System.out.println("In the main method: " + beanB.getBeanA());
}
@Configuration
public static class Config {
@Bean
public BeanA bean1() {
return new BeanA("a1");
}
@Bean
public BeanA bean2() {
return new BeanA("a2");
}
@Bean
public BeanB bean3(@Qualifier("bean2") BeanA theBean) {
BeanB beanB = new BeanB(theBean);
System.out.println("method bean3: beanB created = " + beanB +
"\n with constructor param BeanA = " + theBean);
return beanB;
}
}
}
Output
method bean3: beanB created = BeanB{beanA=BeanA{name='a2'}}
with constructor param BeanA = BeanA{name='a2'}
In the main method: BeanA{name='a2'}
This example demonstrates multiple @Qualifier matches on both sides.
public class InjectParameterByQualifier3 {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(
Config.class);
BeanB beanB = context.getBean(BeanB.class);
System.out.println("In the main method: " + beanB.getBeanA());
}
@Configuration
public static class Config {
@Bean
public BeanA bean1() {
return new BeanA("a1");
}
@Bean
@Qualifier("myBean")
public BeanA bean2() {
return new BeanA("a2");
}
@Bean
public BeanC bean3() {
return new BeanC("c1");
}
@Bean
@Qualifier("myBean2")
public BeanC bean4() {
return new BeanC("c2");
}
@Bean
public BeanB bean5(@Qualifier("myBean") BeanA theBean,
@Qualifier("myBean2") BeanC theBean2) {
BeanB beanB = new BeanB(theBean);
System.out.println("method bean5: beanB created = " + beanB +
"\n with constructor param of type BeanA= " + theBean);
System.out.println("method bean5: theBean2 instance (can also be in as constructor " +
"arg or some " +
"other way): " + theBean2);
return beanB;
}
}
}
Output
method bean5: beanB created = BeanB{beanA=BeanA{name='a2'}}
with constructor param of type BeanA= BeanA{name='a2'}
method bean5: theBean2 instance (can also be in as constructor arg or some other way): BeanC{name='c2'}
In the main method: BeanA{name='a2'}
Original PostThis example shows, how to use @Conditional
to selectively include/exclude beans from registration.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
@Conditional(LocaleConditionUSA.class)
public MyService myBeanA () {
return new MyServiceA();
}
@Bean
@Conditional(LocaleConditionCanada.class)
public MyService myBeanB () {
return new MyServiceB();
}
@Bean
public ClientBean clientBean () {
return new ClientBean();
}
}
Original PostUsing autowiring mode Autowire.BY_NAME
. We need to use @Autowired at the injection point. ServiceBean serviceBean1()
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class AutowireByName {
public static void main (String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(Config.class);
ClientBean bean = context.getBean(ClientBean.class);
bean.doSomething();
}
@Configuration
public static class Config {
@Bean(autowire = Autowire.BY_NAME)
public ClientBean clientBean () {
return new ClientBean();
}
@Bean
public ServiceBean serviceBean1 () {
return new ServiceBean("Service bean 1");
}
@Bean
public ServiceBean serviceBean2 () {
return new ServiceBean("Service bean 2");
}
}
private static class ClientBean {
@Autowired
private ServiceBean serviceBean1;
public void doSomething () {
System.out.println(serviceBean1.getMsg());
}
}
private static class ServiceBean {
private String msg;
public ServiceBean (String msg) {
this.msg = msg;
}
public String getMsg () {
return msg;
}
}
}
Output
Service bean 1
Original PostUsing @Bean element with autowire=Autowire.BY_NAME.
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* In this example we are explicitly giving the bean a name by using @Bean(name =....)
*/
public class AutowireByName2 {
public static void main (String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(Config.class);
ClientBean bean = context.getBean(ClientBean.class);
bean.doSomething();
}
@Configuration
public static class Config {
@Bean(autowire = Autowire.BY_NAME)
public ClientBean clientBean () {
return new ClientBean();
}
@Bean(name = "someOtherServiceBean")
public ServiceBean serviceBean1 () {
return new ServiceBean("Service bean 1");
}
@Bean
public ServiceBean serviceBean2 () {
return new ServiceBean("Service bean 2");
}
}
private static class ClientBean {
private ServiceBean someOtherServiceBean;
@Autowired
public void setSomeOtherServiceBean (ServiceBean serviceBean) {
this.someOtherServiceBean = serviceBean;
}
public void doSomething () {
System.out.println(someOtherServiceBean.getMsg());
}
}
private static class ServiceBean {
private String msg;
public ServiceBean (String msg) {
this.msg = msg;
}
public String getMsg () {
return msg;
}
}
}
Output
Service bean 1
Original PostUsing @Bean element with autowire=Autowire.BY_NAME.
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* In this example we are explicitly giving the bean a name by using @Bean(name =....)
*/
public class AutowireByName3 {
public static void main (String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(Config.class);
ClientBean bean = context.getBean(ClientBean.class);
bean.doSomething();
}
@Configuration
public static class Config {
@Bean(autowire = Autowire.BY_NAME)
public ClientBean clientBean () {
return new ClientBean();
}
@Bean
public ServiceBean serviceBean1 () {
return new ServiceBean("Service bean 1");
}
@Bean(name = "myService")
public ServiceBean serviceBean2 () {
return new ServiceBean("Service bean 2");
}
}
private static class ClientBean {
private ServiceBean serviceBean;
@Autowired
@Qualifier("myService")
public void setServiceBean(ServiceBean serviceBean) {
this.serviceBean = serviceBean;
}
public void doSomething () {
System.out.println(serviceBean.getMsg());
}
}
private static class ServiceBean {
private String msg;
public ServiceBean (String msg) {
this.msg = msg;
}
public String getMsg () {
return msg;
}
}
}
Output
Service bean 2
Original PostUsing @Bean element with autowire=Autowire.BY_NAME.
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* In this example we are explicitly giving the bean a name by using @Bean(name =....)
*/
public class AutowireByName4 {
public static void main (String[] args) {
AnnotationConfigApplicationContext context = new
AnnotationConfigApplicationContext(Config.class);
ClientBean bean = context.getBean(ClientBean.class);
bean.doSomething();
}
@Configuration
public static class Config {
@Bean(autowire = Autowire.BY_NAME)
public ClientBean clientBean () {
return new ClientBean();
}
@Bean
public ServiceBean serviceBean1 () {
return new ServiceBean("Service bean 1");
}
@Bean
@Qualifier("myService")
public ServiceBean serviceBean2 () {
return new ServiceBean("Service bean 2");
}
}
private static class ClientBean {
private ServiceBean serviceBean;
@Autowired
@Qualifier("myService")
public void setServiceBean(ServiceBean serviceBean) {
this.serviceBean = serviceBean;
}
public void doSomething () {
System.out.println(serviceBean.getMsg());
}
}
private static class ServiceBean {
private String msg;
public ServiceBean (String msg) {
this.msg = msg;
}
public String getMsg () {
return msg;
}
}
}
Output
Service bean 2
Original PostConstructor based DI with @Autowired and @Qualifier.
@Configuration
@ComponentScan({"com.logicbig.example.scan"})
public class ConstBasedDIWithScan {
@Bean
public OrderService orderService() {
return new OrderService();
}
public static void main(String... strings) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
ConstBasedDIWithScan.class);
OrderServiceClient bean = context.getBean(OrderServiceClient.class);
bean.showPendingOrderDetails();
}
@Component
public static class OrderServiceClient {
private OrderService orderService;
@Autowired
OrderServiceClient(OrderService orderService) {
this.orderService = orderService;
}
public void showPendingOrderDetails() {
System.out.println(orderService.getOrderDetails("500"));
}
}
}
Original Post