Spring真正的IOC容器

最近看了下spring ioc的文章,加固一下知识。ApplicationContextBeanFactory,谁才是真正的IoC(Inversion of Control)容器

首先看spring文档(beans-introduction)对IoC的描述:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
The org.springframework.beans and org.springframework.context packages are the basis for Spring Framework’s IoC container. The BeanFactory interface provides an advanced configuration mechanism capable of managing any type of object. ApplicationContext is a sub-interface of BeanFactory. It adds:

-Easier integration with Spring’s AOP features

-Message resource handling (for use in internationalization)

-Event publication

Application-layer specific contexts such as the WebApplicationContext for use in web applications.

org.springframework.beans 和 org.springframework.context 两个包是Spring框架中IoC容器的基础。 BeanFactory 接口提供了一种能够管理任何类型对象的高级配置机制。 ApplicationContext 是 BeanFactory 的子接口,它添加了以下特性:

-更易于与Spring AOP特性相整合

-消息资源处理(用于国际化处理)

-事件发布

应用层特定上下文,例如:在Web应用中所使用的 WebApplicationContext

意思就是BeanFactory是底层的IOC容器,ApplicationContext只是复用了BeanFactory接口从而扩展出更多的特性,AOP、消息、事件发布等等。既然是包含关系,那就来验证一下吧

User.java

1
2
3
4
5
6
7
8
9
10
/**
* @description:
* @author: likw
* @date: 2020/06/22
*/
@Data
public class User {
private String name;
private Long id;
}

UserRepository.java

1
2
3
4
5
6
7
8
9

@Data
public class UserRepository {
private Collection<User> users;

private BeanFactory beanFactory;

private ObjectFactory<ApplicationContext> objectFactory;
}

injection-context.xml

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">

<bean id="userRepository" class="top.kenvin.repository.UserRepository" autowire="byType"/>
</beans>

InjectionDemo.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* @description:
* @author: likw
* @date: 2020/06/22
*/
public class InjectionDemo {
public static void main(String[] args) {

ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:/injection-context.xml");

UserRepository userRepository = applicationContext.getBean("userRepository", UserRepository.class);

BeanFactory userFactory = userRepository.getBeanFactory();

System.out.println(userFactory == applicationContext);
}
}

InjectionDemo.java中,这样判断的话,输出肯定是false,因为不是同一对象,但是如果换种写法呢

InjectionDemo.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* @description:
* @author: likw
* @date: 2020/06/22
*/
public class InjectionDemo {
public static void main(String[] args) {

BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/injection-context.xml");

UserRepository userRepository = beanFactory.getBean("userRepository", UserRepository.class);

BeanFactory userFactory = userRepository.getBeanFactory();

System.out.println(userFactory == beanFactory);
}
}

如果这样看都是BeanFactory对象,也是false,为什么注入的都是BeanFactory结果输出的也是false,不妨把两个对象输出来比较一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* @description:
* @author: likw
* @date: 2020/06/22
*/
public class InjectionDemo {
public static void main(String[] args) {

BeanFactory beanFactory = new ClassPathXmlApplicationContext("classpath:/injection-context.xml");

System.out.println("beanFactory: " + beanFactory);

UserRepository userRepository = beanFactory.getBean("userRepository", UserRepository.class);

BeanFactory userFactory = userRepository.getBeanFactory();

System.out.println("userFactory: " + userFactory);

System.out.println(userFactory == beanFactory);
}
}
1
2
3
beanFactory: org.springframework.context.support.ClassPathXmlApplicationContext@27fa135a, started on Sat Apr 04 16:38:54 CST 2020
userFactory: org.springframework.beans.factory.support.DefaultListableBeanFactory@5f2050f6: defining beans [userRepository]; root of factory hierarchy
false

同样是返回BeanFactory对象,通过ClassPathXmlApplicationContext方式获取的BeanClassPathXmlApplicationContext,而通过factory获取的Bean却是DefaultListableBeanFactory。我们可以从继承和实现关系去找到这个原因

1
2
3
4
ClassPathXmlApplicationContext extends AbstractXmlApplicationContext;
AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext;
AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext;
AbstractRefreshableApplicationContext extends AbstractApplicationContext;

从以上继承关系可以得出ClassPathXmlApplicationContext是继承AbstractApplicationContext的,在AbstractApplicationContext中的初始化Bean中

1
2
3
4
5
6
7
8
9
10
11
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

执行prepareBeanFactory(beanFactory)方法时,传入的是ConfigurableListableBeanFactory,而ConfigurableListableBeanFactory中的方法

1
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

getBeanDefinition(String beanName)定义Bean的方法的实现是DefaultListableBeanFactory来完成的,这个技巧是在IDEA上可以发现的

所以在初始化方法prepareBeanFactory(beanFactory)

1
2
3
4
5
6
7
8
9
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
......
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
......

registerResolvableDependency当注册依赖类型是BeanFactory.class时,返回的其实是DefaultListableBeanFactory,这就解释通了,为什么通过userRepository.getBeanFactory();获取的BeanFactory时,输出的是org.springframework.beans.factory.support.DefaultListableBeanFactory

另一个地方也可以验证这种关系

在IDEA中的方法UserRepository userRepository = beanFactory.getBean("userRepository", UserRepository.class);;选中getBean,按Ctrl + Alt + B就可以跳转到实现该方法的类AbstractRefreshableApplicationContext中,

1
2
3
4
5
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
assertBeanFactoryActive();
return getBeanFactory().getBean(name, requiredType);
}

点到getBeanFactory()方法,和刚才一样,利用IDEA查看实现类

返回的beanFactory就是DefaultListableBeanFactory

综上所述:

在用ClassPathXmlApplicationContext获取Bean的时候,其实是ApplicationContext委托DefaultListableBeanFactorygetbean()的,所以真正的IOC容器是BeanFactory的实现类,而ApplicationContextBeanFactory只是定义了一些功能性的接口而已,真正获取Bean的时候是委托BeanFactory的实现类来完成的,有点像代理模式了。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!