Spring Autowiring Using @Configurable

Spring boot Autowired not working in Configuration class

@Import is to add a configuration class into another configuration class.

http://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch04s03.html

@ComponentScan is to scan for components declared in your code, like @Service, @Component, @Repository, among others.

http://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch06s02.html

I think you need to add in your configuration class the @ComponentScan so it can scan the package with your component classes.

@Configuration
@ComponentScan(value = "org.foo.path.baseFolder")
public class MyConfiguration {
@Autowired
protected GlobalPropertiesLoader globalPropertiesLoader;

Why when use @Autowired in @Configuration in Spring failed sometimes?

Because the order to load EagleBeanCreator and EagleServiceBuilder is not definite. You can use @Order or @ConditionalOnClass to make sure EagleBeanCreator initialize first.

Autowire a bean within Spring's Java configuration

If you need a reference to the DataSource bean within the same @Configuration file, just invoke the bean method.

@Bean
public OtherBean someOtherBean() {
return new OtherBean(dataSource());
}

or have it autowired into the @Bean method

@Bean
public OtherBean someOtherBean(DataSource dataSource) {
return new OtherBean(dataSource);
}

The lifecycle of a @Configuration class sometimes prevents autowiring like you are suggesting.

How to Autowire a Spring-annotated service class in a @Configuration class?

Your error is the following (you are returning a null value):

@Bean
public SessionService sessionService() {
return sessionService;
}

Solution

  1. Since your SessionServiceImpl is annotated with @Service, you can just remove the @Bean method and let spring create it. Spring already makes it available for you.

  2. Or, If your SessionServiceImpl wasn't annotated with @Service, you would need the following :

@Bean
public SessionService sessionService() {
return new SessionService();
}

If this doesn't work, it may just be that your SessionServiceImpl is in a package not being scanned by spring (as suggested by @Miloš Milivojević)

You may add @ComponentScan to your Configuration class

@Configuration
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@ComponentScan("com.package.to.sessionServiceImpl-or-higher")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

Why is an @Autowired field within a @Configuration class null?

why must it happen that accountRepository is created before it's used
by new TransferServiceImpl()?

It doesn't. accountRepository may be seen to be null.

From the note in the documentation you linked (its more current version)

Make sure that the dependencies you inject that way are of the
simplest kind only. @Configuration classes are processed quite early
during the initialization of the context and forcing a dependency to
be injected this way may lead to unexpected early initialization.

Whenever possible, resort to parameter-based injection as in the
example above.

Also, be particularly careful with BeanPostProcessor and
BeanFactoryPostProcessor definitions via @Bean. Those should usually
be declared as static @Bean methods, not triggering the instantiation
of their containing configuration class. Otherwise, @Autowired and
@Value won’t work on the configuration class itself since it is being
created as a bean instance too early.

In summary, a Configuration class will end up being just another bean in the application context. As such, it will be processed by all registered BeanPostProcessor beans.

@Autowired is processed by AutowiredAnnotationBeanPostProcessor. Presumably, you're using AnnotationConfigApplicationContext which registers one automatically.

In your example, which is incomplete since

...but determining exactly where the autowired bean definitions are
declared is still somewhat ambiguous

However, we can assume some other configuration provided a bean definition for a AccountRepository bean. Once the application context instantiates the ServiceConfig bean, it can then post process it and inject @Autowired targets.

The only reason an @Autowired target could be null in a @Configuration bean instance is that you tried to read it before an AutowiredAnnotationBeanPostProcessor could process/inject it.

Consider a circular dependency. Take the @Configuration class in your snippet with an additional @ComponentScan of the following classes

@Component
class AccountRepository {
public AccountRepository(Foo foo) {}
}
@Component
class Foo {
public Foo(TransferService ts) {}
}

The @Configuration bean get initialized. AutowiredAnnotationBeanPostProcessor kicks off to process the accountRepository field. It looks for an AccountRepository bean and tries to initialize it. It needs a Foo bean to instantiate it (for constructor injection). It looks for a Foo bean and tries to initialize it. It needs a TransferService bean to instantiate it (for constructor injection). It looks for a TransferService bean and finds the @Bean factory method. It invokes it. The accountRepository hasn't been initialized yet, so remains null. You can verify this by putting a breakpoint in the @Bean method and browsing the stack trace.

Had you used a parameter injection as suggested in the quote above

Whenever possible, resort to parameter-based injection as in the example above.

Spring would've crashed and warned you

Caused by:
org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'accountRepository': Requested bean is
currently in creation: Is there an unresolvable circular reference?


That's the workaround I ended up doing

I can't currently explain this.

Autowire bean from @Configuration

You need to inject the RestTemplate, not the config class

@Autowired
private RestTemplate restTemplate;

instead of:

@Autowired
private RestClientConfig restTemplate;

EDIT

Here is one way to pass your arguments to your class:

//EXAMPLE @Value("${propFile.maxTotalConn}")

@Bean
public RestTemplate createRestTemplate(@Value("${propFile.maxTotalConn}") int maxTotalConn, @Value("${propFile.maxPerChannel}") int maxPerChannel, connTimoutint connTimout) {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(maxTotalConn);
connectionManager.setDefaultMaxPerRoute(maxPerChannel);

...
}

EXPLANATION

Create a properties file (*.properties) and place in your src/main/resources folder. Include your properties in it as the code above suggests. @Value is a Spring annotation that searches for the properties file on the classpath and injects the values while creating your Spring bean.



Related Topics



Leave a reply



Submit