Calling a @Bean Annotated Method in Spring Java Configuration

Calling a @Bean annotated method in Spring java configuration

Yes, Spring does some magic. Check the Spring Docs:

This is where the magic comes in: All @Configuration classes are subclassed at startup-time with CGLIB. In the subclass, the child method checks the container first for any cached (scoped) beans before it calls the parent method and creates a new instance.

This means that the calls to @Bean methods are proxied via CGLIB and therefore the cached version of the bean is returned (a new one is not created).

The default scope of @Beans is SINGLETON, if you specify a different scope such as PROTOTYPE the call will be passed to the original method.

Please note that this is not valid for static methods. As per the spring docs:

Calls to static @Bean methods never get intercepted by the container, not even within @Configuration classes (as described earlier in this section), due to technical limitations: CGLIB subclassing can override only non-static methods. As a consequence, a direct call to another @Bean method has standard Java semantics, resulting in an independent instance being returned straight from the factory method itself.

Method annotated with @Bean is called directly - function calling a bean in a @Service class

The '@Bean' annotation is telling Spring to create a new Spring Bean, using the logic in the method that it decorates.
This is usually done in Configuration classes, much like you are doing in your AuthorizationServiceConfig (https://github.com/arocketman/SpringBlog/blob/master/src/main/java/com/arocketman/github/config/AuthorizationServerConfig.java).

What you are doing here is calling the annotated method in order to fetch the Spring-managed bean. This is not allowed. How you would go about fixing this, while keeping your passwordencoder as a bean, is by autowiring the bean into this server, just like you do with the UserRepository.

So you would move the annotated method to a configuration class (either an existing or new one), and then autowire it into this Service.
Something like this:

@Autowired
private BCryptPasswordEncoder passwordEncoder;

Your 'save' method then becomes:

 public void save(User user){
user.setPassword(passwordEncoder.encode(user.getPassword()));
userRepository.save(user);
}

I hope this helps you out.
Good luck with your project!

Calling a bean method from another method annotated as Bean

No, it wouldn't.

SampleTest has a singleton scope which is the default, so even if you call the method "directly", Spring will make sure that there is only one instance per container.

Spring Boot: Calling a @Bean method several times

Actually each time you get the same object. As it was said, the default scope for spring beans is singleton which means there is only one instance of your class in Spring container.

Why do you receive the same object each time?

It's because @Configuration annotation that you used in your class implicates creation of proxy (which is subclass of your class annotated with @Configuration). This proxy stores singleton and returns reference to it whenever you call @Bean method.

Why @Bean method returns reference instead of creating object as it is in implementation?

Proxy also overrides your @Bean method.

Different behavior in calling @Bean annotated methods

The "magic" of proxying method calls annotated with @Bean and returning instances from the Spring context happens only in configuration beans (like here: @SpringJUnitConfig(MyBean.class)).

But when you create a new instance as return new MyBean(), the @Configuration annotation is ignored and the object is registered as a normal bean (@Bean MyBean myBean()) but not a configuration. That's why the methods calls otherBean() create always a new instance.

Spring boot Bean annotation and instance variable flow in Configuration

Actually, I don't think this is the standard way of creation.

As when you annotate the method with @Bean, you mean you want to ask Spring to help you to manage the bean. Therefore it makes no sense to store the bean instance by yourself as a local variable.

Instead of storing the instance in the class field, you should ask Spring to give you the instance instead.

There are multiple ways to do that.

  1. Specify RestTemplate as a parameter in @Bean method. In case you have asked Spring to manage multiple RestTemplate instance, which is possible. Then you should specify the parameter name same as @Named which is userRestTemplate, so that Spring can find the correct restTemplate properly.
@Configuration
public class UserConfiguration{
@Bean
@Named("userRestTemplate")
public RestTemplate userRestTemplate(RestTemplateBuilder restTemplateBuilder) {
RestTemplate restTemplate = restTemplateBuilder.build();
// this.restTemplate = restTemplate; // no this restTemplate instance setting;
return restTemplate;
}

@Bean
public UserDetail userDetail(RestTemplate userRestTemplate) {
UserDetail user = new UserDetail();
user.setTemplate(userRestTemplate);
return user;
}
}

  1. Use @Autowired Annotation.
@Configuration
public class UserConfiguration{
@Autowired
private RestTemplate restTemplate;

@Bean
@Named("userRestTemplate")
public RestTemplate userRestTemplate(RestTemplateBuilder restTemplateBuilder) {
RestTemplate restTemplate = restTemplateBuilder.build();
//restTemplate.getMessageConverters().add(0, createMappingJacksonHttpMessageConverter());
// this.restTemplate = restTemplate; // again no setting this, okay.
return restTemplate;
}

@Bean
public UserDetail userDetail() {
UserDetail user = new UserDetail();
user.setTemplate(restTemplate);
return user;
}
}

The advantage of asking Spring to manage java beans, instead of managing by ourselves.
You would have the advantage to use Spring AOP, ...



Related Topics



Leave a reply



Submit