1 不加@Configuration注解情况1
- 两个POJO类A和B,注意A和B都没有标注@Component等注解。
- 配置类App,注意App类并没有标注任何注解。App内部使用@Bean注解标注了两个方法generateA和generateB。
- 主类Main,我们创建IOC容器时将App.class作为参数传入。
package com.woods.configuration_test;
/**
* @author woods
* Created on 2020-08-04
*/
public class A {
public A() {
System.out.println("A construction");
}
}
package com.woods.configuration_test;
/**
* @author woods
* Created on 2020-08-04
*/
public class B {
public B() {
System.out.println("B construction");
}
}
package com.woods.configuration_test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author woods
* Created on 2020-07-04
*/
public class App {
@Bean
public B generateB() {
return new B();
}
@Bean
public A generateA() {
generateB();
return new A();
}
}
package com.woods.configuration_test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author woods
* Created on 2020-07-04
*/
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(App.class);
}
}
上面代码的运行结果如下。可以看到,generateB()方法被调用了两遍。
B construction
B construction
A construction
问题1:App类是SpringIOC容器中的Bean吗?
回答:是的。register(componentClasses)方法将传入的类转化成AnnotatedGenericBeanDefinition并注册到BeanFactory中。
在Main里new AnnotationConfigApplicationContext(App.class);,
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
/*
* 注意,有父类的情况下先调用父类的构造方法
* 进一步讲,有父类的情况下调用顺序为,
* 父类的静态代码块(即父类执行类初始化clinit方法),子类静态代码块(clinit方法),父类非静态代码块,父类构造方法,子类非静态代码块,子类构造方法
* */
this();
register(componentClasses);
refresh();
}
问题2:是谁处理了@Bean标注的方法?
ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法中,会调用ConfigurationClassParser的processConfigurationClass方法,处理@Bean注解标注的类。
2 不加@Configuration注解情况2
- 四个POJO类A、B、C和D,其中C标注了@Component注解,C中使用@Bean注解标注了方法generateC。
- 配置类App,注意App类并没有标注任何注解。App内部使用@Bean注解标注了两个方法generateA和generateB。
- 主类Main,我们创建IOC容器时将App.class作为参数传入。
package com.woods.configuration_test;
/**
* @author woods
* Created on 2020-08-04
*/
public class A {
public A() {
System.out.println("A construction");
}
}
package com.woods.configuration_test;
/**
* @author woods
* Created on 2020-08-04
*/
public class B {
public B() {
System.out.println("B construction");
}
}
package com.woods.configuration_test;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
/**
* @author woods
* Created on 2020-09-11
*/
@Component
public class C {
public C() {
System.out.println("C construction");
}
@Bean
public D generateD() {
return new D();
}
}
package com.woods.configuration_test;
/**
* @author woods
* Created on 2020-09-11
*/
public class D {
public D() {
System.out.println("D construction");
}
}
package com.woods.configuration_test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author woods
* Created on 2020-07-04
*/
@ComponentScan("com.woods.configuration_test")
public class App {
@Bean
public B generateB() {
return new B();
}
@Bean
public A generateA() {
generateB();
return new A();
}
}
package com.woods.configuration_test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author woods
* Created on 2020-07-04
*/
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(App.class);
}
}
上面代码的运行结果如下。
C construction
D construction
B construction
B construction
A construction
3 加@Configuration注解
- 两个POJO类A和B,注意A和B都没有标注@Component等注解。
- 配置类App,注意App类并没有标注任何注解。App内部使用@Bean注解标注了两个方法generateA和generateB。
- 主类Main,我们创建IOC容器时将App.class作为参数传入。
package com.woods.configuration_test;
/**
* @author woods
* Created on 2020-08-04
*/
public class A {
public A() {
System.out.println("A construction");
}
}
package com.woods.configuration_test;
/**
* @author woods
* Created on 2020-08-04
*/
public class B {
public B() {
System.out.println("B construction");
}
}
package com.woods.configuration_test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author woods
* Created on 2020-07-04
*/
@Configuration
public class App {
@Bean
public B generateB() {
return new B();
}
@Bean
public A generateA() {
generateB();
return new A();
}
}
package com.woods.configuration_test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author woods
* Created on 2020-07-04
*/
public class Main {
public static void main(String[] args) {
AnnotationConfigApplicationContext configApplicationContext = new AnnotationConfigApplicationContext(App.class);
}
}
上面代码的运行结果如下。
B construction
A construction
问题1:为什么这里只打印了一个B construction?
回答:如果配置类(这里是App类)上加了@Configuration注解,那么Spring会为App类生成cglib代理。在执行App内部@Bean标注的方法时,会先看Bean是否已经存在,如果存在直接从BeanFactory中取出。