spring框架在整个java体系中属于教科书般的存在,理解spring读懂spring是每一个javaer在成长路上都必须迈过去的一步。但是spring源码晦涩难懂,类关系也非常复杂,读懂spring并不是一件很轻松的事。所以这里介绍一下理解spring源码的方法,希望可以帮到你。
理解spring先从工厂模式入手
spring框架中有一个顶级的接口叫做BeanFactory,这就是spring的核心。从字面意思来看spring就是实例的工厂,作为初学者可以先这么理解并不算错。那么入手spring我们得先搞清楚什么是工厂模式,举个例子:我们开发的软件通常都带有支付功能,并且给用户选择的支付方式并不止一种,假如有微信支付、支付宝支付、招商信用卡支付这三种,且将来也可能会有更多。调用这些支付渠道方法都是不一样的,为了代码的可维护性和扩展性,我们通常会把不同的支付方式放在不同的类里,用户选择那种支付方式我们就创建那种支付方式的实例来调用支付方法。
以上说的“需要那种支付方式我们就创建那种支付方式的实例”,这就是工厂模式的基本逻辑。“为了代码的可维护性和扩展性”,这说的其实就是遵循编程思想里的开闭原则,也就是说工厂模式是遵循开闭原则编程思想的一种方法。下面用代码来实现一下工厂模式:
//支付渠道接口
public interface IPayChannel{
boolean pay(Order order);
}
//创建三种支付方式实现类
public class WechatPayChannelImpl implements IPayChannel{
public boolean pay(Order order){
//省略业务逻辑
return isSuccess;
}
}
public class AlipayPayChannelImpl implements IPayChannel{
public boolean pay(Order order){
//省略业务逻辑
return isSuccess;
}
}
public class CmbPayChannelImpl implements IPayChannel{
public boolean pay(Order order){
//省略业务逻辑
return isSuccess;
}
}
//创建支付渠道工厂类
public class PayChannelFactory{
private static Map payChannelMap = new HashMap<>();
static{
payChannelMap.put(1,new WechatPayChannelImpl());
payChannelMap.put(2,new AlipayPayChannelImpl());
payChannelMap.put(3,new CmbPayChannelImpl());
}
public static IPayChannel getPayChannelInstance(int paytype){
IPayChannel instance = payChannelMap.get(paytype);
if(instance == null){
throw new IllegalArgumentException();
}
return instance;
}
}
//调用工厂获取实例
public Context{
public void orderPay(Order order){
IPayChannel payChannel = PayChannelFactory.getPayChannelInstance(order.getPayType());
boolean success = payChannel.pay(order);
}
}
以上就是工厂模式的实现,因为支付渠道的实例可以复用,我们在工厂类初始化的时候为每个渠道创建一个实例就够了。实际上spring也是这么做的,它的底层也维护着一个存放所有实例的Map集合。所以,你从工厂模式的角度去理解spring会简单很多,spring框架的基本思想就是一个工厂模式。
为什么我们称作spring是容器呢
工厂模式是理解spring的第一步,你可以大概从上面的factory类中知道spring做了什么,但远不止这些。你之所以用spring是因为你的项目中有成百上千个类的实例需要管理,这么一个“大工程”你需要把他托付给一个框架。spring基本实现就是依赖注入框架,也可以叫做依赖注入容器(Dependency Injection Container),简称 DI 容器。
DI 容器的核心功能有三个:配置解析、对象创建和对象生命周期管理。我们先自己写一个DI容器来了解一下DI的实现逻辑。
首先,我们先看一下配置解析
在工厂模式中,工厂类要创建哪个类对象是事先确定好的,并且是写死在工厂类代码中的。作为一个通用的框架来说,框架代码跟应用代码应该是高度解耦的,DI 容器事先并不知道应用会创建哪些对象,不可能把某个应用要创建的对象写死在框架代码中。所以,我们需要通过一种形式,让应用告知 DI 容器要创建哪些对象。这种形式就是我们说的配置。
我们将需要由 DI 容器来创建的类对象和创建类对象的必要信息(使用哪个构造函数以及对应的构造函数参数都是什么等等),放到配置文件中。容器读取配置文件,根据配置文件提供的信息来创建对象。
我们来看一下spring容器的配置文件,spring容器读取这个配置文件,并解析出DataSource,JdbcTemplate 两个对象,JdbcTemplate依赖于DataSource。
public class DataSource{
private String url;
private String username;
private String password;
private String driver;
public DataSource(String url,String username,String password,String driver){
this.username = username;
this.password = password;
this.url = url;
this.driver = driver;
}
}
public class JdbcTemplate{
private DataSource dataSource;
public JdbcTemplate(DataSource dataSource){
this.dataSource = dataSource;
}
public void test() {
System.out.println("Hello World!");
}
}
配置文件beans.xml:
spirng会根据xml定义把bean先解析成BeanDefinition对象。
public interface BeanConfigParser {
List parse(InputStream inputStream);
List parse(String configContent);
}
public class XmlBeanConfigParser implements BeanConfigParser {
@Override
public List parse(InputStream inputStream) {
String content = null;
// TODO:...
return parse(content);
}
@Override
public List parse(String configContent) {
List beanDefinitions = new ArrayList<>();
// TODO:... return beanDefinitions;
}
}
public class BeanDefinition {
private String id;
private String className;
private List constructorArgs = new ArrayList<>();
// 省略必要的getter/setter/constructors
public static class ConstructorArg {
private boolean isRef;
private Class type;
private Object arg;
// 省略必要的getter/setter/constructors
}
}
其次,我们看一下对象创建
在spring中默认创建的对象是单例的,spring也可以根据你的配置创建多例的对象(每一次都new出一个新对象)。这里为了demo简洁就只创建单例的对象。spring有一个默认的工厂类叫做DefaultListableBeanFactory
,这个类定义了对象创建逻辑和放置bean的容器。实际上创建bean的主要技术点就是Java中的反射语法。
public class DefaultListableBeanFactory {
private ConcurrentHashMap singletonObjects = new ConcurrentHashMap<>();
private ConcurrentHashMap beanDefinitions = new ConcurrentHashMap<>();
public void addBeanDefinitions(List beanDefinitionList) {
for (BeanDefinition beanDefinition : beanDefinitionList) {
this.beanDefinitions.putIfAbsent(beanDefinition.getId(), beanDefinition);
}
for (BeanDefinition beanDefinition : beanDefinitionList) {
createBean(beanDefinition);
}
}
public Object getBean(String beanId) {
BeanDefinition beanDefinition = beanDefinitions.get(beanId);
if (beanDefinition == null) {
throw new NoSuchBeanDefinitionException("Bean is not defined: " + beanId);
}
return createBean(beanDefinition);
}
protected Object createBean(BeanDefinition beanDefinition) {
if (singletonObjects.contains(beanDefinition.getId())) {
return singletonObjects.get(beanDefinition.getId());
}
Object bean = null;
try {
Class beanClass = Class.forName(beanDefinition.getClassName());
List args = beanDefinition.getConstructorArgs();
if (args.isEmpty()) {
bean = beanClass.newInstance();
} else {
Class[] argClasses = new Class[args.size()];
Object[] argObjects = new Object[args.size()];
for (int i = 0; i < args.size(); ++i) {
BeanDefinition.ConstructorArg arg = args.get(i);
if (!arg.getIsRef()) {
argClasses[i] = arg.getType();
argObjects[i] = arg.getArg();
} else {
BeanDefinition refBeanDefinition = beanDefinitions.get(arg.getArg());
if (refBeanDefinition == null) {
throw new NoSuchBeanDefinitionException("Bean is not defined: " + arg.getArg());
}
argClasses[i] = Class.forName(refBeanDefinition.getClassName());
argObjects[i] = createBean(refBeanDefinition);
}
}
bean = beanClass.getConstructor(argClasses).newInstance(argObjects);
}
} catch (ClassNotFoundException | IllegalAccessException
| InstantiationException | NoSuchMethodException | InvocationTargetException e) {
throw new BeanCreationFailureException("", e);
}
if (bean != null ) {
singletonObjects.putIfAbsent(beanDefinition.getId(), bean);
return singletonObjects.get(beanDefinition.getId());
}
return bean;
}
}
然后提供一个上下文来作为初始化Bean和获取Bean的入口。
public interface ApplicationContext {
Object getBean(String beanId);
}
public class ClassPathXmlApplicationContext implements ApplicationContext {
private DefaultListableBeanFactory beansFactory;
private BeanConfigParser beanConfigParser;
public ClassPathXmlApplicationContext(String configLocation) {
this.beansFactory = new DefaultListableBeanFactory();
this.beanConfigParser = new XmlBeanConfigParser();
loadBeanDefinitions(configLocation);
}
private void loadBeanDefinitions(String configLocation) {
InputStream in = null;
try {
in = this.getClass().getResourceAsStream("/" + configLocation);
if (in == null) {
throw new RuntimeException("Can not find config file: " + configLocation);
}
List beanDefinitions = beanConfigParser.parse(in);
beansFactory.addBeanDefinitions(beanDefinitions);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
// TODO: log error
}
}
}
}
@Override
public Object getBean(String beanId) {
return beansFactory.getBean(beanId);
}
}
public class Demo {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
JdbcTemplate jdbcTemplate= (JdbcTemplate) applicationContext.getBean("jdbcTemplate");
jdbcTemplate.test();
//...
}
}
最后,看一下生命周期管理
spring对实例的生命周期管理有懒加载、初始化方法、实例销毁。实现起来也比较简单,懒加载和初始化方法其实就是在bean创建的时候根据约定的配置来做相应的事情。实例销毁销毁就是删除spring容器中初始化好的对象。
// 在配置文件中约定两个参数
public class BeanDefinition {
private String id;
private String className;
private List constructorArgs = new ArrayList<>();
private boolean lazyInit;
private String initMethod;
// ...
}
然后在BeanFactory
中做相应的判断和处理。
public class DefaultListableBeanFactory{
private ConcurrentHashMap singletonObjects = new ConcurrentHashMap<>();
private ConcurrentHashMap beanDefinitions = new ConcurrentHashMap<>();
// ....省略之前的定义
public void addBeanDefinitions(List beanDefinitionList) {
for (BeanDefinition beanDefinition : beanDefinitionList) {
this.beanDefinitions.putIfAbsent(beanDefinition.getId(), beanDefinition);
}
for (BeanDefinition beanDefinition : beanDefinitionList) {
if (beanDefinition.isLazyInit() == false && beanDefinition.isSingleton()) {
createBean(beanDefinition);
}
}
}
public Object getBean(String beanId) {
BeanDefinition beanDefinition = beanDefinitions.get(beanId);
if (beanDefinition == null) {
throw new NoSuchBeanDefinitionException("Bean is not defined: " + beanId);
}
return createBean(beanDefinition);
}
protected Object createBean(BeanDefinition beanDefinition) {
if (singletonObjects.contains(beanDefinition.getId())) {
return singletonObjects.get(beanDefinition.getId());
}
Object bean = null;
try {
Class beanClass = Class.forName(beanDefinition.getClassName());
List args = beanDefinition.getConstructorArgs();
if (args.isEmpty()) {
bean = beanClass.newInstance();
} else {
Class[] argClasses = new Class[args.size()];
Object[] argObjects = new Object[args.size()];
for (int i = 0; i < args.size(); ++i) {
BeanDefinition.ConstructorArg arg = args.get(i);
if (!arg.getIsRef()) {
argClasses[i] = arg.getType();
argObjects[i] = arg.getArg();
} else {
BeanDefinition refBeanDefinition = beanDefinitions.get(arg.getArg());
if (refBeanDefinition == null) {
throw new NoSuchBeanDefinitionException("Bean is not defined: " + arg.getArg());
}
argClasses[i] = Class.forName(refBeanDefinition.getClassName());
argObjects[i] = createBean(refBeanDefinition);
}
}
bean = beanClass.getConstructor(argClasses).newInstance(argObjects);
if (refBeanDefinition.getInitMethod() != null){
beanClass.getMethod(refBeanDefinition.getInitMethod()).invoke(bean,null);
}
}
} catch (ClassNotFoundException | IllegalAccessException
| InstantiationException | NoSuchMethodException | InvocationTargetException e) {
throw new BeanCreationFailureException("", e);
}
if (bean != null ) {
singletonObjects.putIfAbsent(beanDefinition.getId(), bean);
return singletonObjects.get(beanDefinition.getId());
}
return bean;
}
public void destroy(){
singletonObjects.clear();
beanDefinitions.clear();
}
}
了解真正的spring
了解了spring大概的实现思路我们就可以来看spring的源码了。我们可以写一个简单demo来看一下spring如何初始化一个bean。
先随便写一个类,实现它的构造方法。
public class Hello {
public Hello() {
System.out.println("Hello bean instantiation");
}
}
然后写一个配置类,把上面的类对象放到spring容器里。
@Configuration
public class IConfig{
public IConfig() {
System.out.println("IConfig bean instantiation");
}
@Bean
public Hello hello() {
return new Hello();
}
}
再启动spring容器,debug分析源码。
public class DemoApplication {
public static void main(String[] args) {
//启动spring容器
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(IConfig.class);
//从容器中获取bean
Hello hello = (Hello) annotationConfigApplicationContext.getBean("hello");
System.out.println(hello);
}
}
点进去源码你会看到这个构造方法:
public AnnotationConfigApplicationContext(Class>... componentClasses) {
this();
register(componentClasses);
refresh();
}
这个构造方法里面有一个refresh()
方法,这个方法就是spring创建bean的全部过程了。
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
// Prepare this context for refreshing.
//准备刷新(初始化环境变量和准备早期的一些监听器以及事件)
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
//通知子容器工厂进行refresh
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
//按照当前环境准备bean工厂(添加AwareProcessor后置处理器,支持xxxAware接口处理功能)
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
//处理子类bean工厂的后置处理器
postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
// Invoke factory processors registered as beans in the context.
//执行bean工厂的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
//注册bean的后置处理器,以拦截Bean的创建过程
registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
// Initialize message source for this context.
//初始化MessageSource以支持i18n
initMessageSource();
// Initialize event multicaster for this context.
//初始化当前应用的事件多播器,spring事件编程
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
//预留给子类进行bean初始化工作方法
onRefresh();
// Check for listener beans and register them.
//发现和注册所有的监听器
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
//完成所有Bean工厂的实例,初始化所有非懒加载的单实例Bean
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
//发布完成事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
contextRefresh.end();
}
}
}
spring的创建过程大概有13步,理解这13步做了什么整个spring就清楚了。
在源码中会看到这些核心的类,在这里再解释一下帮助你去理解。
- BeanFactory:Bean工厂。工厂帮我们制造了所有的组件、管理组件。
- FactoryBean:工厂Bean,是spring容器里另一种类型的Bean,帮我们构建复杂的Bean
- BeanDefinition:Bean定义,存放所有bean的元信息
- BeanDefinitionRegistry:bean定义的注册中心
- BeanDefinitionReader:Bean定义的读取器
- BeanFactoryPostProcessor: Bean工厂的后置处理器,可以拦截并干预Bean工厂的创建过程
- BeanPostProcessor:Bean的后置处理器,可以拦截并干预Bean的创建过程
- Aware(BeanFactory):感知。
- xxxAware。容器中的组件需要一些感兴趣的信息(一般不是我们自己的组件,而是系统组件)
- 利用回调,把系统组件赋值给我们,我们进行接收使用