Spring 最重要的概念是 IOC 和 AOP,其中IOC又是Spring中的根基:
我们可以使用AnnotationConfigApplicationContext来获取通过注解注入到容器中的bean。下面我们来简单测试一下:
我们先写一个配置类,里面定义要扫描的包路径:
@Configuration("com.jihu")
@ComponentScan("com.jihu")
public class AppConfig {
}
然后我们定义一个常用的bean:
@Component
public class TestGetBean {
}
然后我们再来使用annotationConfigApplicationContext来获取扫描的bean.
public class TestAnnotationConfigContext {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
System.out.println(applicationContext.getBean("testGetBean"));
}
}
-------------------------------------------
com.jihu.bean.TestGetBean@12f40c25
Process finished with exit code 0
这样我们就可以获取到容器中的bean了。
我们先来使用Idea看一下这个类的继承图:
可以看到它继承了很多接口,比如BeanDefinitionRegistry、AbstractApplicationContext等,拥有很多功能。
那我们就来详细的看看他是如何初始化bean和获取bean的。
我们可以使用AnnotationConfigApplicationContext的构造方法来初始化容器。
// 接收一个component类的class, 这里我们一般会把自己的配置类写进入(配置类中有配置包的扫描路径等)
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
// 1、首先会调用父类的构造方法,其次调用自己的构造
// 1.1、调用父类构造生成一个defaultListableBeanFactory:
// public GenericApplicationContext() { this.beanFactory = new DefaultListableBeanFactory();}
// 1.2、调用自己的构造初始化一个读取器AnnotatedBeanDefinitionReader和一个扫描器ClassPathBeanDefinitionScanner
this();
// 2、将我们传入的配置类(带有@Configuration注解)注册成一个bean
register(componentClasses);
refresh();
}
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
//注解bean定义读取器,主要作用是用来读取被注解的了bean
private final AnnotatedBeanDefinitionReader reader;
//扫描器,它仅仅是在我们外部手动调用 .scan 等方法才有用,常规方式是不会用到scanner对象的
private final ClassPathBeanDefinitionScanner scanner;
/**
* Create a new AnnotationConfigApplicationContext that needs to be populated
* through {@link #register} calls and then manually {@linkplain #refresh refreshed}.
*/
public AnnotationConfigApplicationContext() {
//会隐式调用父类的构造方法,初始化DefaultListableBeanFactory
//初始化一个Bean读取器
this.reader = new AnnotatedBeanDefinitionReader(this);
//初始化一个扫描器,它仅仅是在我们外部手动调用 .scan 等方法才有用,常规方式是不会用到scanner对象的
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
}
无参构造方法中就是对读取器reader和扫描器scanner进行了实例化。
reader的类型是AnnotatedBeanDefinitionReader,可以看出它是一个 “打了注解的Bean定义读取器”。
scanner的类型是ClassPathBeanDefinitionScanner,它仅仅是在外面手动调用.scan方法,或者调用参数为String的构造方法,传入需要扫描的包名才会用到,像这样方式传入的配置类是不会用到这个scanner对象的。
当我们调用AnnotationConfigApplicationContext的构造方法的时候会调用其父类GenericApplicationContext的构造方法来初始化一个DefaultListableBeanFactory。
/**
* Create a new GenericApplicationContext.
* @see #registerBeanDefinition
* @see #refresh
*/
public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}
我们来看一个DefaultListableBeanFactory的类图结构:
Spring中比较核心的是BeanFactory的实现类是DefaultListableBeanFactory。
它实现了很多接口,表示,它拥有很多功能:
在AnnotationConfigApplicationContext的构造方法中实例化了一个AnnotatedBeanDefinitionReader。
public AnnotationConfigApplicationContext() {
// 解析 @Configuration 添加注解的配置类
this.reader = new AnnotatedBeanDefinitionReader(this);
// spring提供api来动态扫描注解
// 一般供拓展spring的时候用的,内部Spring并不使用这个对象
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
这个构造方法中做了一下的事情:
我们来看看AnnotatedBeanDefinitionReader的构造方法到底做了什么:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry) {
this(registry, getOrCreateEnvironment(registry));
}
我们再跟进去:
public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
Assert.notNull(environment, "Environment must not be null");
this.registry = registry;
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
继续跟进到registerAnnotationConfigProcessors方法:
public static void registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
registerAnnotationConfigProcessors(registry, null);
}
…
好吧。再进最后一次:
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
.......................
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
.......................
}
这个方法太长了,我们简单看中间一段就好。
1、这里首先会判断容器中是否已经注册了ConfigurationClassPostProcessor Bean。
2、如果不存在(当然这里肯定是不存在的),就通过RootBeanDefinition的构造方法获得ConfigurationClassPostProcessor的BeanDefinition,RootBeanDefinition是BeanDefinition的子类。
3、执行registerPostProcessor方法,registerPostProcessor方法内部就是注册Bean,当然这里注册其他Bean也是一样的流程。
BeanDefinition是用来描述Bean的,里面存放着关于Bean的一系列信息,比如Bean的作用域,Bean所对应的Class,是否懒加载,是否Primary等等。