前面两篇文章,我们从mybatis-spring的插件包出发,探究如何将第三方框架集成到spring中,也知道了mybatis中使用了FactoryBean+ImportBeanDefifinitionRegistrar+@Import对mapper进行注入。
不过我们在前两篇文章中仍然遗留很多疑点,例如
1、ImportBeanDefifinitionRegistrar是在什么时机被调用的,怎么被回调的,为什么不能搭配@Compnent一起使用?
2、mybatis是如何扩展spring的扫描器的?(扫描自定义注解或某个包下的类),而spring本身又是如何扫描的?
3、FeactoryBean的工作原理是什么?
4、BeanFactoryPostProcess的工作原理?怎么回调的?回调时机?本身是如何注入到spring中的?其子类的原理和作用?可以获取修改beandefinition,为什么不能注册?为什么有List<BeanFactoryPostProcess>这个集合?
5、什么是但理财、BeanDefinitionMap、@import是如何工作的?
下面我们才算开始学习spring源码,我们可以带着这些疑问,从源码的角度去解释这些疑问。
-----------------------------------------------------------------------------------------
一、什么是spring容器?
上面是spring官方对容器的一个解释:
BeanFactory接口提供了一种高级配置机制,能够管理任何类型的对象。ApplicationContext是BeanFactory的子接口,该子接口补充了下面的功能:
1、更容易与Spring的AOP特性集成
2、消息资源处理(用于国际化)
3、事件发布
4、应用程序层特定的上下文,如web应用程序中使用的WebApplicationContext。
简而言之,BeanFactory提供了配置框架和基本功能,ApplicationContext添加了更多企业特定的功能。ApplicationContext是BeanFactory的一个完整超集。
我们可以简单的总结spring容器:容器由spring多个组件组成(如各种后置处理器、扩展接口),用于管理任何类型对象,并提供多种应用功能。其主要存在两个分支:BeanFactory、ApplicationContext(两者都可以叫做spring的容器,只是提供的功能不同)。BeanFactory相当于一个标配版容器(提供了基本的对对象的管理),而ApplicationContext是选配豪华版容器(不仅提供了父接口的功能,还提供了依赖注入、各种注解扫描、更简单的aop集成、事件发布、国际化等等)。
Integrated lifecycle management----------------
Automatic BeanPostProcessor
registration---------@Autowried等依赖注入功能
Automatic BeanFactoryPostProcessor registration-----------------
Convenient MessageSource access (for internationalization)------国际化功能
Built-in ApplicationEvent publication mechanism---------事件发布功能
我们从三个方面来举例两者的不同:(以ApplicationContext比BeanFactory多出了依赖注入、各种注解扫描、事件发布这三个功能举例)
1、依赖注入功能
2、注解扫描功能
3、事件发布功能(springboot中大量使用事件发布功能进行扩展)
代码实例:
1)、SpringContainerBean
package com.spring.demo.container;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* 测试依赖注入、注解扫描、事件发布等功能
* */
@Slf4j
@Component
public class SpringContainerBean implements InitializingBean {
//1、测试能否进行依赖注入
@Autowired
C c;
@Autowired
ApplicationContext context;
public SpringContainerBean(){
System.out.println("create SpringContainerBean Object");
}
//2、测试能否扫描到这个注解
//3、context.publishEvent()----测试事件发布功能
@PostConstruct
public void init(){
System.out.println("SpringContainerBean init PostConstruct");
context.publishEvent(new ABeanInitEvent(context));
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("SpringContainerBean init afterPropertiesSet");
}
}
2)、依赖注入的类C
@Component
@Slf4j
public class C {
public C(){
System.out.println("create c Object");
}
}
3)、事件类
/**
* 发布事件类不需要进行注入操作(监听的类需要进行注入操作)
*/
public class ABeanInitEvent extends ApplicationContextEvent {
public ABeanInitEvent(ApplicationContext source) {
super(source);
}
}
4)、监听事件类
/**
* 监听ABeanInitEvent事件(需要进行注入)
* */
@Component
public class ABeanListener implements ApplicationListener<ABeanInitEvent> {
@Override
public void onApplicationEvent(ABeanInitEvent event) {
System.out.println("event----" + event.getClass().getSimpleName());
}
}
5)、ApplicationContext容器的启动配置类ContextConfig
@Component
@ComponentScan("com.spring.demo.container")
public class ContextConfig {
}
现在我们可以使用两个不同的容器,看看他们的功能区分:
启动ApplicationContext容器
public class ApplicationContextTest {
public static void main(String[] args) {
//获取ApplicationContext容器(传入ContextConfig配置类是为了让其自动调用register、refresh方法,也可以不传手动调用这两个方法)
//这个ContextConfig就是我们平常写的Application类
AnnotationConfigApplicationContext conext = new AnnotationConfigApplicationContext(ContextConfig.class);
}
}
查看打印结果:
启动BeanFactory容器
public class BeanFactoryTest {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SpringContainerBean.class);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
beanFactory.registerBeanDefinition("springContainerBean", beanDefinition);
//BeanFactory注册的bean默认都是懒加载,需要手动getBean才会进行初始化
beanFactory.getBean(SpringContainerBean.class);
}
}
查看打印结果:
从上面的结果看到,BeanFatory容器确实不支持依赖注入(c构造方法没被打印),注解扫描(@
@PostConstruct注解方法没被执行),事件发布。但两者都支持对对象的基本管理(对对象进行注入,对实现了InitializingBean的方法调用)
那么BeanFatory既然本身没支持这些功能,我们可以自己给他扩展吗?
答案是可以的,例如我们以依赖注入功能为例,看看怎么实现:
我们先注释掉SpringContainerBean 的context代码
package com.spring.demo.container;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* 测试依赖注入、注解扫描、事件发布等功能
* */
@Slf4j
@Component
public class SpringContainerBean implements InitializingBean {
//1、测试能否进行依赖注入
@Autowired
C c;
/*@Autowired
ApplicationContext context;*/
public SpringContainerBean(){
System.out.println("create SpringContainerBean Object");
}
//2、测试能否扫描到这个注解
//3、context.publishEvent()----测试事件发布功能
/* @PostConstruct
public void init(){
System.out.println("SpringContainerBean init PostConstruct");
context.publishEvent(new ABeanInitEvent(context));
}*/
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("SpringContainerBean init afterPropertiesSet");
}
}
修改BeanFactory代码:
public class BeanFactoryTest {
public static void main(String[] args) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(SpringContainerBean.class);
//builder.getBeanDefinition().setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
beanFactory.registerBeanDefinition("springContainerBean", beanDefinition);
BeanDefinitionBuilder builderC = BeanDefinitionBuilder.genericBeanDefinition(C.class);
AbstractBeanDefinition beanDefinitionC = builderC.getBeanDefinition();
beanFactory.registerBeanDefinition("c", beanDefinitionC);
//@Autowired的依赖注入原理就是依靠这个AutowiredAnnotationBeanPostProcessor,所以我们把他交给容器即可
AutowiredAnnotationBeanPostProcessor auto = new AutowiredAnnotationBeanPostProcessor();
auto.setBeanFactory(beanFactory);
beanFactory.addBeanPostProcessor(auto);
//BeanFactory注册的bean默认都是懒加载,需要手动getBean才会进行初始化
//beanFactory.getBean(C.class);
beanFactory.getBean(SpringContainerBean.class);
}
}
如果知道@Autowrited注解的源码,应该就能知道@Autowired的依赖注入原理就是依靠这个AutowiredAnnotationBeanPostProcessor,所以我们需要把他交给容器。
这里还要注意一点:我们是没有去手动getBean(C.class)的,并且所以BeanFactory注入的bean都是懒加载的,如果我们依赖注入成功,则会打印C类的构造方法。
此时我们看下打印结果,发现依赖注入的功能实现了:
2、BeandefinitionMap?
前面说到一个对象被转化为一个BeanDefinition,然后基本会被put到BeandefinitionMap。而BeandefinitionMap存在两种BeanDefinition,一种spring自己内部的Beandefinition,一种我们通过spring的扩展注入的。
现在我们以ApplicationContex容器为例
1)、ApplicationContex容器中实例化了一个DefaultListableBeanFactory 从AnnotationConfigApplicationContext为入口: new AnnotationConfigApplicationContext ------------------》this()构造方法(有父类会先调用父类构造方法) ------------------》父类GenericApplicationContext的构造方法 -----------------》父类中存在一个属性DefaultListableBeanFactory beanFactory;并且构造方法会赋值this.beanFactory = new DefaultListableBeanFactory();
实际上就是以DefaultListableBeanFactory(BeanFactory容器为壳进行扩展自己的功能)为壳。
2)、进入DefaultListableBeanFactory
进入DefaultListableBeanFactory后我们可以发现一个属性------>
/** Map of singleton and non-singleton bean names, keyed by dependency type. */ Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); 其中key----bean的名字,values----某个类的Beandefinition对象
3)、开始断点查找扫描后BeanDefinition put进beanDefinitionMap的代码
经过不断debug,当我们执行完AnnotationConfigApplicationContext--->refresh();------>
invokeBeanFactoryPostProcessors()方法后beanDefinitionMap出现了我们自己注入的BeanDefinition对象
-----------------------invokeBeanFactoryPostProcessors()方法执行前
---------------------invokeBeanFactoryPostProcessors()方法执行后
所以我们可以推断 invokeBeanFactoryPostProcessors()方法完成了对我们自己注入的对象的扫描+put beanDefinitionMap的过程(执行这个方法之前Map没有值)
------------------------------invokeBeanFactoryPostProcessors方法执行前各个BeanDefinition的含义
(即此时未扫描我们自己注入的对象/类)
我们先不进去invokeBeanFactoryPostProcessors方法看其扫描的原理,我们先来看看这几个BeanDefinition的用处:
contextConfig -> 这是我们自己注册的BeanDefinition,因为实例化容器时需要传入这个类,所以就一同被注入了。
下面则是spring内部注册的Beandefinition:
1)、internalConfigurationAnnotationProcessor -> 对应的ConfigurationClassPostProcessor
该类是spring中非常重要的类,完成了spring的大部分工作(这里不细讲)
2)、internalEventListenerFactory" -> 对应的类DefaultEventListenerFactory
3)、internalEventListenerProcessor" -> 对应的类EventListenerMethodProcessor
4)、internalAutowiredAnnotationProcessor-> 对应类AutowiredAnnotationBeanPostProcessor
解析1@Autowrited注解依赖注入
5)、internalCommonAnnotationProcessor-> 对应的类CommonAnnotationBeanPostProcessor
解析@Resource注解依赖注入等功能,还有其他功能
这几个BeanDefinition是什么时候实例化出来的?
AnnotationConfigApplicationContext---》this()----->AnnotatedBeanDefinitionReader类的构造器
--->AnnotationConfigUtils类的registerAnnotationConfigProcessors()方法
/**
* Register all relevant annotation post processors in the given registry.
* @param registry the registry to operate on
* @param source the configuration source element (already extracted)
* that this registration was triggered from. May be {@code null}.
* @return a Set of BeanDefinitionHolders, containing all bean definitions
* that have actually been registered by this call
*/
public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {
DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
if (beanFactory != null) {
if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
}
if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
}
}
Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);
//--------------------实例化BenDefinition
if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
//-------1、实例化出对应的BeanDefinition
RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
def.setSource(source);
//--------2、registerPostProcessor方法将其put到BeanDefinitionMap中
beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}
// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.
if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition();
try {
def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,
AnnotationConfigUtils.class.getClassLoader()));
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);
}
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));
}
if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));
}
return beanDefs;
}
put到BeanDefinitionMap中是在registerPostProcessor方法中执行的,调用链:
registerPostProcessor() --->BeanDefinitionRegistry接口的registerBeanDefinition()方法 ----->其实现类DefaultListableBeanFactory中将BeanDefinition put到BeanDefinitionMap中
下篇我们开始讲invokeBeanFactoryPostProcessors()方法怎么扫描我们自己注入的对象/类,然后put到BeanDefinitionMap中的。