最近看了下spring ioc
的文章,加固一下知识。ApplicationContext
和 BeanFactory
,谁才是真正的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 @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 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 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 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@27f a135a, started on Sat Apr 04 16 :38 :54 CST 2020 userFactory: org.springframework.beans.factory.support.DefaultListableBeanFactory@5f 2050f6: defining beans [userRepository]; root of factory hierarchyfalse
同样是返回BeanFactory
对象,通过ClassPathXmlApplicationContext
方式获取的Bean
是ClassPathXmlApplicationContext
,而通过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) { prepareRefresh(); ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 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.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
委托DefaultListableBeanFactory
来getbean()
的,所以真正的IOC容器是BeanFactory
的实现类,而ApplicationContext
和BeanFactory
只是定义了一些功能性的接口而已,真正获取Bean的时候是委托BeanFactory
的实现类来完成的,有点像代理模式了。