重新认识Spring(1)-真正的IOC容器

ApplicationContextBeanFactory,谁才是真正的IoC(Inversion of Control)容器

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

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

/**
 * @description:
 * @author: likw
 * @date: 2020/4/4
 */
@Data
public class User {
    private String name;
    private Long id;
}

UserRepository.java

/**
 * @description:
 * @author: likw
 * @date: 2020/4/4
 */
@Data
public class UserRepository {
    private Collection<User> users;

    private BeanFactory beanFactory;

    private ObjectFactory<ApplicationContext> objectFactory;
}

injection-context.xml

<?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

/**
 * @description:
 * @author: likw
 * @date: 2020/4/4
 */
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

/**
 * @description:
 * @author: likw
 * @date: 2020/4/4
 */
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,不妨把两个对象输出来比较一下

/**
 * @description:
 * @author: likw
 * @date: 2020/4/4
 */
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);
    }
}
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。我们可以从继承和实现关系去找到这个原因

ClassPathXmlApplicationContext extends AbstractXmlApplicationContext;
AbstractXmlApplicationContext extends AbstractRefreshableConfigApplicationContext;
AbstractRefreshableConfigApplicationContext extends AbstractRefreshableApplicationContext;
AbstractRefreshableApplicationContext extends AbstractApplicationContext;

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

@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中的方法

BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

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

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

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中,

@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的实现类来完成的,有点像代理模式了。

# spring 
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×