A.java:
@Configuration
@Import(B.class)
class A {
@Bean
public X x(Y y) {
return new X(y);
}
}
B.java:
@Configuration
class B {
@Bean
public Y y() {
return new Y();
}
// And some other beans are defined
}
Will all beans defined in B.java
be instantiated when bean x
is instantiated? Since the file B.java
is imported by A.java
.
CodePudding user response:
A Test:
A simple test to visualize your answer:
class ATest {
private static final Logger LOGGER = LoggerFactory.getLogger(A.class);
private ApplicationContext ctx;
@BeforeEach
void setUp() {
ctx = new AnnotationConfigApplicationContext(A.class);
}
@Test
void test() {
for (String beanName: ctx.getBeanDefinitionNames()) {
LOGGER.info("BEAN: " beanName);
}
}
}
Output:
[main] INFO be.dog.d.steven.A - BEAN: org.springframework.context.annotation.internalConfigurationAnnotationProcessor
[main] INFO be.dog.d.steven.A - BEAN: org.springframework.context.annotation.internalAutowiredAnnotationProcessor
[main] INFO be.dog.d.steven.A - BEAN: org.springframework.context.event.internalEventListenerProcessor
[main] INFO be.dog.d.steven.A - BEAN: org.springframework.context.event.internalEventListenerFactory
[main] INFO be.dog.d.steven.A - BEAN: a
[main] INFO be.dog.d.steven.A - BEAN: org.company.B
[main] INFO be.dog.d.steven.A - BEAN: y
[main] INFO be.dog.d.steven.A - BEAN: x
As you can see, @Import
did make the application context include all beans in class B as expected.
The first 4 beans are always created, even if you use just one empty class annotated with @Configuration
to build the application context. The fifth bean that will always be created is the annotated class used to create the context.
In practice:
Although this works fine, it is cleaner to have your application do a @ComponentScan(basePackages = "org.company")
in a certain package or folder. This way you do not always have to add new components to the @Import
annotation. (You might also not want to scan the whole project when you are working on a bigger project, rather just folders containing actual components.)
You can however use @Import
on test classes to only load an isolated part of the context for that test.
You can also set the logging level of the Spring Framework to DEBUG in the application.properties:
logging.level.org.springframework=DEBUG
This way you can also check the logs of your application to see what beans get created.
CodePudding user response:
First I ran the sample that is posted by you. Then I tested one sample with following variation,
@Configuration
@Import(B.class)
class A {
@Bean
public X x(Y y) {
return new X(y);
}
}
And then the last variation as following,
@Slf4j
@Configuration
class B {
@Bean
public Y y() {
log.info("Creating bean Y in B {}", System.currentTimeMillis());
return new Y();
}
@Bean
public Z z(){
log.info("Creating bean Z in B {}", System.currentTimeMillis());
return new Z();
}
// And some other beans are defined
}
Here is what I inferred from my observations,
- A bean is always when you're using the annotation
@Bean
, bean is declared from a class which is annotated with either@Component
,@Configuration
or@Service
and your component class is part of your declared package in@ComponentScan
, then Spring will always register your bean. I can safely say that @Import has very little to do with bean creation. - Upon running second first(one with default constructor) multiple times, I found bean X created before bean Y.
- Upon running second variation where I declared more than one bean in class B, the order of bean creation was Y, X and then Z.
@Import is just used to group your bean definition source as I found here on Baeldung, @Import