Reputation: 4501
Say I have this dependency in a Spring @Configuration
:
@Bean
public SomeClass someClass(SomeClass1 someClass1, SomeClass2 someClass2, ...) {
return new SomeClass(someClass1, someClass2, ...);
}
Say I want do do something in @PostConstruct
that includes someClass
dependency:
@PostConstruct
public void init() {
someClass.doSomething();
}
This cannot be injected:
@PostConstruct
public void init(SomeClass someClass) {
someClass.doSomething();
}
causes:
Caused by: java.lang.IllegalStateException: Lifecycle method annotation requires a no-arg method: ...
This cannot be autowired in the same config like this:
@Autowire
private SomeClass someClass;
@Bean
public SomeClass someClass(SomeClass1 someClass1, SomeClass2 someClass2, ...) {
return new SomeClass(someClass1, someClass2, ...);
}
as that leads to:
Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'globalBus': Requested bean is currently in creation: Is there an unresolvable circular reference?
A config can be split (so @Bean
goes to the other config) and @Import
-ed by this one and it works OK. Probably other solutoins exist - e.g. creating a separate initialization bean or so.
Is there a way to do this within one @Configuration
?
Edit
As requested by @SotiriosDelimanolis, a sscce for the exception when using @Autowired
:
public class ConfigPostConstructDependenciesPrb {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
ctx.getBean(Service.class);
ctx.close();
}
public static class Service {
private final Dependency dependency;
public Service(Dependency dependency) {
this.dependency = dependency;
}
public void work() {
System.out.println(dependency.getNum());
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Service [dependency=");
sb.append(dependency);
sb.append("]");
return sb.toString();
}
}
public static class Dependency {
private final int num;
public Dependency(int num) {
this.num = num;
}
public int getNum() {
return this.num;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("SomeClass1 [num=");
sb.append(num);
sb.append("]");
return sb.toString();
}
}
@Configuration
public static class BaseConfig {
@Autowired
private Service service;
@Bean
public Dependency dependency() {
return new Dependency(42);
}
@Bean
public Service service(Dependency dependency) {
return new Service(dependency);
}
@PostConstruct
public void init() {
service.work();
}
}
@Configuration
@Import(BaseConfig.class)
public static class Config {
@Autowired
private Service service;
}
}
Upvotes: 11
Views: 20572
Reputation: 1700
(Tested in Spring 4.3.6)
Create a nested class inside your @Configuration and put there declarations of @Autowired service
and @PostConstruct init()
:
@Configuration
public static class BaseConfig {
//...
@Bean
public Service service(Dependency dependency) {
return new Service(dependency);
}
@Configuration
public static class Setup {
@Autowired
private Service service;
@PostConstruct
public void init() {
service.work();
}
}
}
Below is your full example updated accordingly.
Notice that you don't have to add explicit reference to BaseConfig.Setup
(look at the @Import
annotation before Config
class - it only refers to BaseConfig
itself).
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.*;
import javax.annotation.PostConstruct;
public class ConfigPostConstructDependenciesPrb {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(Config.class);
ctx.getBean(Service.class);
ctx.close();
}
public static class Service {
private final Dependency dependency;
public Service(Dependency dependency) {
this.dependency = dependency;
}
public void work() {
System.out.println(dependency.getNum());
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Service [dependency=");
sb.append(dependency);
sb.append("]");
return sb.toString();
}
}
public static class Dependency {
private final int num;
public Dependency(int num) {
this.num = num;
}
public int getNum() {
return this.num;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("SomeClass1 [num=");
sb.append(num);
sb.append("]");
return sb.toString();
}
}
@Configuration
public static class BaseConfig {
@Bean
public Dependency dependency() {
return new Dependency(42);
}
@Bean
public Service service(Dependency dependency) {
return new Service(dependency);
}
@Configuration
public static class Setup {
@Autowired
private Service service;
@PostConstruct
public void init() {
service.work();
}
}
}
@Configuration
@Import(BaseConfig.class)
public static class Config {
@Autowired
private Service service;
}
}
Upvotes: 4
Reputation: 170
Try this way:
public class ConfigPostConstructDependenciesPrb {
public static void main(String[] args) {
try {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(BaseConfig.class);
ctx.registerShutdownHook();
ctx.getBean(Service.class);
ctx.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
@Configuration
class BaseConfig {
@Autowired
private Service service;
@Bean
public Dependency dependency() {
return new Dependency(42);
}
@Bean
public Service service(Dependency dependency) {
return new Service(dependency);
}
@PostConstruct
public void init() {
this.service.work();
}
}
class Dependency {
private int num;
public Dependency() {
}
public Dependency(int num) {
this.num = num;
}
public int getNum() {
return this.num;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("SomeClass1 [num=");
sb.append(num);
sb.append("]");
return sb.toString();
}
}
class Service {
private Dependency dependency;
public Service() {
}
public Service(Dependency dependency) {
this.dependency = dependency;
}
public void work() {
System.out.println(dependency.getNum());
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Service [dependency=");
sb.append(dependency);
sb.append("]");
return sb.toString();
}
}
Upvotes: 0