Spring 源码学习过程:
1. 搞明白IOC能做什么?
IOC是用为用户创建、管理实例对象的。用户需要实例对象时只需要向IOC容器获取就行了,不用自己去创建,从而达到与具体类解耦。
2. IOC是怎么做到的,即它的实现步骤是怎么样的?
2.1 用户配置bean定义
我们使用Spring IOC时有几种方式来配置bean定义呢?
xml的方式:
<bean id="abean" class="com.study.spring.samples.ABean"> <constructor-arg type="String" value="abean01"></constructor-arg> <constructor-arg ref="cbean"></constructor-arg> </bean> <bean id="cbean" class="com.study.spring.samples.CBean"> <constructor-arg type="String" value="cbean01"></constructor-arg> </bean>
注解方式:
package com.study.spring.samples; import com.study.spring.context.config.annotation.Autowired; import com.study.spring.context.config.annotation.Component; import com.study.spring.context.config.annotation.Qualifier; import com.study.spring.context.config.annotation.Value; @Component(initMethodName = "init", destroyMethodName = "destroy") public class ABean { private String name; private CBean cb; @Autowired private DBean dbean; @Autowired public ABean(@Value("leesmall") String name, @Qualifier("cbean01") CBean cb) { super(); this.name = name; this.cb = cb; System.out.println("调用了含有CBean参数的构造方法"); } public ABean(String name, CCBean cb) { super(); this.name = name; this.cb = cb; System.out.println("调用了含有CCBean参数的构造方法"); } public ABean(CBean cb) { super(); this.cb = cb; } }
Java-based容器配置方式:
@Configuration public class AppConfig { @Bean public MyService myService() { return new MyServiceImpl(); } }
上面的AppConfig类等价于:
<beans>
<bean />
</beans>
想了解java容器配置的朋友请看这篇文章:
2.2 IOC容器加载bean定义
用户以上面的三种方式配置bean定义以后,Spring IOC容器怎么来加载用户的bean定义呢,这就需要我们来告诉它了
xml的方式告诉Spring IOC容器怎么加载bean定义:
//类路径下加载xml配置文件创建bean定义 ApplicationContext context = new ClassPathXmlApplicationContext("application.xml"); //文件系统下加载xml配置文件创建bean定义 ApplicationContext context1 = new FileSystemXmlApplicationContext("e:/study/application.xml"); //通用的xml方式加载xml配置文件创建bean定义 ApplicationContext context3 = new GenericXmlApplicationContext("file:e:/study/application.xml");
注解方式告诉Spring IOC容器怎么加载bean定义:
xml方式指定注解要扫描的基础包:
<beans> <context:component-scan base-package="com.study" /> </beans>
注解方式指定注解要扫描的基础包:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(basePackages="com.study") public class AppConfig { @Bean public MyService myService() { return new MyServiceImpl(); } }
也可在代码中通过API指定注解扫描的基础包:
// 扫描注解的方式创建bean定义 ApplicationContext ctx= new AnnotationConfigApplicationContext(); ctx.scan("com.study"); ctx.refresh(); MyService myService = ctx.getBean(MyService.class);
Java-based容器配置告诉Spring IOC容器怎么加载bean定义:
使用AnnotationConfigApplicationContext告诉Spring IOC容器怎么加载bean定义配置
跟实例化一个ClassPathXmlApplicationContext时将Spring XML文件用作输入相似,在实例化一个AnnotationConfigApplicationContext时能够使用@Configuration类作为输入。这就等等于Spring容器全然零XML配置:
public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); MyService myService = ctx.getBean(MyService.class); myService.doStuff(); }
AnnotationConfigApplicationContext不局限于仅仅使用@Configuration类。不论什么@Component或JSR-330注解的类都能够作为AnnotationConfigApplicationContext构造器的输入:
public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(MyServiceImpl.class, Dependency1.class, Dependency2.class); MyService myService = ctx.getBean(MyService.class); myService.doStuff(); }
使用无參的构造器实例化AnnotationConfigApplicationContext,然后使用register()方法对容器进行配置。这样的方式在以编程方式构造一个AnnotationConfigApplicationContext时非常实用:
public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.register(AppConfig.class, OtherConfig.class); ctx.register(AdditionalConfig.class); ctx.refresh(); MyService myService = ctx.getBean(MyService.class); myService.doStuff(); }
启用scan(String…)的组件扫描:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @Configuration @ComponentScan(basePackages="com.study") public class AppConfig { @Bean public MyService myService() { return new MyServiceImpl(); } }
scan方法扫描:
public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.scan("com.study"); ctx.refresh(); MyService myService = ctx.getBean(MyService.class); }
二、搞明白Spring IOC的从整体到部分
IOC整体是由以上几部分组成起来工作的
三、找到Spring IOC入口,先理清楚主干流程,然后再去研究各个流程的细节
我们从上面的使用示例,很清楚地看到,我们使用Spring IOC,只需要使用Spring提供的ApplicationContext这个API。ApplicationContext就是IOC容器。ApplicationContext就是Spring IOC的入口,源码的学习就从它开始!
1. ApplicationContext是什么
首先来了解ApplicationContext都是什么,即它都有哪些角色、责任。它通过继承很多接口而有很多角色。
ApplicationContext继承的接口(角色)如下:
每个角色拥有的职责(方法):
再来了解 ApplicationContext 自己中定义的方法:
2. Application的子实现
说明:
从 AbstarctApplicationContext 之后分为两类:xml 配置方式的实现和通用实现。它们的基本使用示例如下:
package com.study.leesmall.spring; import org.springframework.beans.factory.xml.XmlBeanDefinitionReader; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ClassPathBeanDefinitionScanner; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.context.support.FileSystemXmlApplicationContext; import org.springframework.context.support.GenericApplicationContext; import org.springframework.context.support.GenericXmlApplicationContext; import com.study.leesmall.spring.service.Abean; import com.study.leesmall.spring.service.CombatService; //Spring不同的方式创建bean实例使用代码示例 @Configuration public class TestApplication { public static void main(String[] args) { //类路径下加载xml配置文件创建bean定义 ApplicationContext context1 = new ClassPathXmlApplicationContext("application.xml"); CombatService cs = context1.getBean(CombatService.class); cs.doInit(); cs.combating(); //文件系统下加载xml配置文件创建bean定义 ApplicationContext context2 = new FileSystemXmlApplicationContext("e:/study/application.xml"); cs = context2.getBean(CombatService.class); cs.doInit(); cs.combating(); //通用的xml方式加载xml配置文件创建bean定义 ApplicationContext context3 = new GenericXmlApplicationContext("file:e:/study/application.xml"); cs = context3.getBean(CombatService.class); cs.doInit(); cs.combating(); // 扫描注解的方式创建bean定义 ApplicationContext context4 = new AnnotationConfigApplicationContext(TestApplication.class); CombatService cs2 = context4.getBean(CombatService.class); cs2.combating(); //通用的方式加载xml配置文件或者扫描指定包下的类创建bean定义 System.out.println("------------------------------------------------------"); GenericApplicationContext context5 = new GenericApplicationContext(); new XmlBeanDefinitionReader(context5).loadBeanDefinitions("classpath:application.xml"); new ClassPathBeanDefinitionScanner(context5).scan("com.study.leesmall.spring.service"); // 一定要刷新 context5.refresh(); cs2 = context5.getBean(CombatService.class); cs2.combating(); Abean ab = context5.getBean(Abean.class); ab.doSomething(); } @Bean public CombatService getCombatService() { return new CombatService(120); } }
接下来,可以打开每个子去了解它们分别加入了什么、实现了什么?
1)ConfigurableApplicationContext 加入了什么:
说明:
void addApplicationListener(ApplicationListener<?> listener):这个方法添加监听 在这里可以进行发布订阅监听的工作
void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor):这个方法可以对bean工厂进行获取前后的AOP增强
void refresh() throws BeansException, IllegalStateException:这个方法是用来刷新IOC容器的,当往IOC容器里面注册了新的Bean定义时,调用这个方法去创建bean实例
2)AbstractApplicationContext里面对前面的接口就开始有具体的实现了,比如addApplicationListener、addBeanFactoryPostProcessor、refresh等等
3)通用的实现GenericApplicationContext
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry { private final DefaultListableBeanFactory beanFactory; @Nullable private ResourceLoader resourceLoader; private boolean customClassLoader = false; private final AtomicBoolean refreshed = new AtomicBoolean();
它实现了BeanDefinitionRegistry接口,该接口定义了bean定义信息的注册行为。即我们可以直接往GenericApplicationContext中注册bean定义。
了解一下BeanDefinitionRegistry中定义的行为:
都有谁实现了 BeanDefinitionRegistry 接口:
GenericApplicationContext中持有DefaultListableBeanFactory,GenericApplicationContext的bean定义注册委托给了持有的DefaultListableBeanFactory
org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(String, BeanDefinition)对应代码:
@Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); if (beanDefinition instanceof AbstractBeanDefinition) { try { ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName); if (existingDefinition != null) { if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition); } else if (existingDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (logger.isInfoEnabled()) { logger.info("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else if (!beanDefinition.equals(existingDefinition)) { if (logger.isDebugEnabled()) { logger.debug("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } else { if (logger.isTraceEnabled()) { logger.trace("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + existingDefinition + "] with [" + beanDefinition + "]"); } } this.beanDefinitionMap.put(beanName, beanDefinition); } else { if (hasBeanCreationStarted()) { // Cannot modify startup-time collection elements anymore (for stable iteration) synchronized (this.beanDefinitionMap) { this.beanDefinitionMap.put(beanName, beanDefinition); List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } else { // Still in startup registration phase this.beanDefinitionMap.put(beanName, beanDefinition); this.beanDefinitionNames.add(beanName); this.manualSingletonNames.remove(beanName); } this.frozenBeanDefinitionNames = null; } if (existingDefinition != null || containsSingleton(beanName)) { resetBeanDefinition(beanName); } }