Spring Framework 源码分析

环境搭建

Spring5.x+Gradle 4.3.1 + JDK1.8.0_181 + Windows64 + IDEA 2017

Spring 5:

git clone -b 5.0.x https://github.com/spring-projects/spring-framework.git

推荐先 fork 该项目, 然后 clone 下来, 这样修改可以保存到自己的仓库,也可以向官方提 pull request.

Jdk

Gradle

IDEA

Gradle 设置

环境变量 GRADLE_HOME, 值为 Gradle 根目录

环境变量 GRADLE_USER_HOME,表示下载的 jar 包放在那个仓库, 可以指定文件夹路径

IDEA 使用技巧

双击类名/方法名/文件名, copy reference 可以拿到 类名/方法名 的全路径

ctrl + 鼠标左键:跳到方法的定义位置

ctrl + alt + B: 可以快速定位接口/方法有哪些实现类,跳到方法的实现位置

断点技巧:设置断点后, 右击断点可以设置断点条件, 如: name.equals("myapp")

调试时可以选中代码, 右键, 选择 Evaluate Expression, 然后 Evaluate

控制台技巧:断点按步骤、按每一行、跳出方法、恢复代码执行、断点管理等

常用 Gradle 指令

--stacktrace: 打印异常信息

-x:排除某个 task

--task: 查看当前 build.gradle 有哪些 task

javadocJar: 一个生成 doc 和 doc Jar 包的 task

gradle javadocJar --stacktrace -x :spring-beans:javadoc

编译

IOC 功能

spring-aop 和 spring-context 模块用到日志模块(spring 的日志用的是 apache jcl 日志框架), 为了不报错, 可以在 spring-framework 项目的 build.gradle 下, 加入如下依赖:

compile group: 'commons-logging', name: 'commons-logging', version: '1.1.1'

新建 gradle 项目,在 build.gradle 的 dependencies 中加入

compile project(':spring-context')

直接 build 会报如下错误:

Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/cglib/core/NamingPolicy

需要先执行 spring-core 的 cglibRepackJar 任务和 objenesisRepackJar 任务,

cd spring-core

gradle cglibRepackJar objenesisRepackJar

或者你也可以执行 spring-core 的 complieTestJava 任务(懒汉行为, 不推荐), 然后再执行新建项目的 build。

IOC 分析

配置类, @Configuration 可以将本类中 @Bean 注解的 Bean 加入到 IOC 容器中, @ComponentScan 扫描某个包下 @Component 注解的 Bean 加入 IOC 容器中

package top.waterlaw.ioc;

import org.springframework.context.annotation.ComponentScan;

@ComponentScan("top.waterlaw.ioc")
public class AppConfig {
}

Test 类:

package top.waterlaw.ioc;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {
    /**
     * 把类扫描出来
     * 把 bean 实例化
     */
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext =
                new AnnotationConfigApplicationContext(AppConfig.class);
    }
}

循环依赖

Bean A 依赖于 B, Bean B 同时又依赖于 A, 如何解决?

Bean A 创建过程

getBean(name="A") --> 找不到 new Bean(name="A") --> new Bean A 对应的类对象实例-->需要注入 Bean B, 打断,设置 Bean 的中间状态

--> getBean(name="B") --> 找不到 new Bean(name="B")--> new Bean B 对应的类对象实例-->需要注入 A

-->getBean(name="A")-->找不到, new Bean(name="A"), A 正在创建中

org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean

org.springframework.beans.factory.support.AbstractBeanFactory#markBeanAsCreated

这里才会真正创建 Bean

org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton(java.lang.String, org.springframework.beans.factory.ObjectFactory<?>)

org.springframework.beans.factory.support.SimpleInstantiationStrategy#instantiate(

org.springframework.beans.factory.support.RootBeanDefinition, java.lang.String, org.springframework.beans.factory.BeanFactory)

return BeanUtils.instantiateClass(constructorToUse);

org.springframework.beans.BeanUtils#instantiateClass(java.lang.reflect.Constructor, java.lang.Object...)

return (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
                    KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));

上述创建 Bean 对象实例

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean

populateBean(beanName, mbd, instanceWrapper);

会初始化注入依赖 Bean 对象实例

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean

getBeanPostProcessors() // 是一个 CopyOnWriteArrayList

有 7 个 BeanPostProcess

image-20191202030756848.png

下面的代码中的 AutowiredAnnotationBeanPostProcessor 会生成依赖对象的实例

if (hasInstAwareBpps || needsDepCheck) {
            if (pvs == null) {
                pvs = mbd.getPropertyValues();
            }
            PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
            if (hasInstAwareBpps) {
                for (BeanPostProcessor bp : getBeanPostProcessors()) {
                    if (bp instanceof InstantiationAwareBeanPostProcessor) {
                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
                        pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
                        if (pvs == null) {
                            return;
                        }
                    }
                }
            }
            if (needsDepCheck) {
                checkDependencies(beanName, mbd, filteredPds, pvs);
            }
        }

org.springframework.beans.factory.annotation.

AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues

org.springframework.beans.factory.annotation.

AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
    Field field = (Field) this.member;
    Object value;
    if (this.cached) {
        value = resolvedCachedArgument(beanName, this.cachedFieldValue);
    }
    else {
        //- 生成依赖对象的实例
        DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
        desc.setContainingClass(bean.getClass());
        Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
        Assert.state(beanFactory != null, "No BeanFactory available");
        TypeConverter typeConverter = beanFactory.getTypeConverter();
        try {
            value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
        }
        catch (BeansException ex) {
            throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
        }
        // ...
    }
}

Bean 的生命周期

Spring 中 bean 的生命周期

new 对象 --> AOP --> 执行 Bean 的生命周期方法-->自动注入-->xxxx

普通单例 Bean

特殊单例 Bean: FactoryBean

Ibatis 的 MapperFactoryBean 是一个 FactoryBean, 我们来自己实现一个 FactoryBean

现在项目中引入 mybatis 依赖包, 我们先借用下 mybatis 的一些注解比如 @Select

compile group: 'org.mybatis', name: 'mybatis', version: '3.5.0'

定义一个 Dao

package top.waterlaw.mybatis;

import org.apache.ibatis.annotations.Select;

import java.util.List;
import java.util.Map;

public interface CityDao {

    @Select("select * from city")
    List<Map<String, Object>> queryAll();
}

再来定义一个 Service

package top.waterlaw.mybatis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class CityService {
    @Autowired
    CityDao cityDao;

    public CityService() {
        System.out.println("init CityService");
    }

    public void queryAll() {
        System.out.println(cityDao.queryAll());
        System.out.println("query all");
    }
}

这样是无法注入的,想自己管理 Bean 生命周期而不是交给 Spring 管理, 得自己实现 FactoryBean 并注册到 ImportBeanDefinitionRegistrar 接口,自定义 MyFactoryBean

package top.waterlaw.mybatis;

import org.springframework.beans.factory.FactoryBean;
import java.lang.reflect.Proxy;

//org.mybatis.spring.mapper.MapperFactoryBean // mybatis 提供了一个非常牛逼的类

public class MyFactoryBean implements FactoryBean<Object> {// MyFactoryBean 自己实现类似 MapperFactoryBean

    Class<?> interfaces;

    public MyFactoryBean() {
        System.out.println("init factory bean ");
    }

    public MyFactoryBean(Class<?> interfaces) {
        System.out.println("init MyFactoryBean...");
        this.interfaces = interfaces;
    }

    // 只实例化一个 Bean
//  @Override
//  public Object getObject() throws Exception {
//      Class<?>[] interfaces = new Class[]{CityDao.class};
//      ClassLoader classLoader = FactoryBean.class.getClassLoader();
//      CityDao cityDao = (CityDao) Proxy.newProxyInstance(classLoader, interfaces, new IBatisInvokeHandle());
//      return cityDao;
//  }

    // 有多个 Mapper 需要实例化, 需要Class 类型成员变量 interfaces 和构造方法
    @Override
    public Object getObject() throws Exception {
        Class<?>[] interfaces = new Class<?>[]{this.interfaces};
        ClassLoader classLoader = FactoryBean.class.getClassLoader();
        Object o = Proxy.newProxyInstance(classLoader, interfaces, new IBatisInvokeHandle());
        return o;
    }
    // 只实例化一个 Bean
//  @Override
//  public Class<?> getObjectType() {
//      return CityDao.class;
//  }

    @Override
    public Class<?> getObjectType() {
        return interfaces;
    }
}

JDK 代理:

package top.waterlaw.mybatis;

import org.apache.ibatis.annotations.Select;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class IBatisInvokeHandle implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("exec sql");
        System.out.println(method.getAnnotation(Select.class).value()[0]);
        return null;
    }
}

将 MyFactoryBean 注册到 ImportBeanDefinitionRegistrar

package top.waterlaw.mybatis;

import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportFactoryPostProcessor implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions
        (AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {


        //- 不能这样写, 会交给 spring 去 new 对象
//      BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CityDao.class);
        /**
         * <bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean">
         *  <property name="mapperInterface" value="org.mybatis.spring.sample.mapper.UserMapper" />
         *  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
         *  </bean>
         */
        // mybatis 提供 MapperFactoryBean // mybatis 提供了一个非常牛逼的类
        // 如何扫描到 MyFactoryBean, 写一个注解 @MyScan, 带有 @Import, 将注解配置到 Config 类
        // 暴露的是 FactoryBean 接口, 而不是 Bean 接口
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MyFactoryBean.class);
        AbstractBeanDefinition beanDefinition = builder.getBeanDefinition();
        // xml 设置 Dao, Bean 实例化后会用到
        beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("top.waterlaw.mybatis.CityDao");
        registry.registerBeanDefinition("cityDao", beanDefinition);
    }
}

@MyScan 注解将 MyImportFactoryPostProcessor 注入到 Spring 配置类以注入 Spring

package top.waterlaw.mybatis;

import org.springframework.context.annotation.Import;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Import(MyImportFactoryPostProcessor.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyScan {
}

配置类

package top.waterlaw.mybatis;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;

import javax.sql.DataSource;

@ComponentScan("top.waterlaw.mybatis")
//@MapperScan("top.waterlaw.xxx")   // 扫描多个 Mapper
@MyScan
@Configuration
public class AppConfig {
}

测试下:

package top.waterlaw.mybatis;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class IbatisTest {


    public static void main(String[] args) {
        AnnotationConfigApplicationContext ac =
                new AnnotationConfigApplicationContext(AppConfig.class);

        ac.getBean(CityService.class).queryAll();
    }
}

打印:

十二月 13, 2019 5:44:21 上午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@a09ee92: 

startup date [Fri Dec 13 05:44:21 CST 2019]; root of context hierarchy
init CityService
init MyFactoryBean...
十二月 13, 2019 5:44:22 上午 org.springframework.jdbc.datasource.DriverManagerDataSource setDriverClassName
信息: Loaded JDBC driver: com.mysql.cj.jdbc.Driver
exec sql
select * from city
null
query all

原型 Bean

原型 Bean 在使用的时候才初始化, 具体在 getBean() 方法

扩展点

扩展点主要是 BPP(BeanPostProcessor), 当然还有 BeanFactoryPostProcessor 等

BeanFactoryPostProcessor

Bean 工厂接口, 包含一个方法

package org.springframework.beans.factory.config;

import org.springframework.beans.BeansException;
public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}

可以写一个 Bean (@Component), 然后重写 postProcessBeanFactory 方法,该方法暴露了 BeanFactory

package top.waterlaw.ioc;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.stereotype.Component;

@Component
public class MyBeanFactoryPostProcess implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        System.out.println("MyBeanFactoryPostProcess.....");
        // 获取 bean name='c' 的 Bean
        GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanFactory.getBeanDefinition("c");
        System.out.println(beanDefinition.getBeanClassName());
        // 修改 bean 对应的类为 TestService
        beanDefinition.setBeanClass(TestService.class);
    }
}

定义一个 beanName = "c" 的 bean,

package top.waterlaw.ioc;

import org.springframework.stereotype.Component;

@Component("c")
public class CityService {

    public CityService(){
        System.out.println("init CityService..");
    }
}

TestService 如下

package top.waterlaw.ioc;

public class TestService {
    public TestService() {
        System.out.println("init TestService");
    }
}

运行 Test 类控制台打印

十二月 02, 2019 1:20:47 上午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@a09ee92: 

startup date [Mon Dec 02 01:20:47 CST 2019]; root of context hierarchy
MyBeanFactoryPostProcess.....
top.waterlaw.ioc.CityService
init TestService

说明 BeanName 被修改为 TestService

AOP 功能

spring-context 模块已经引用了 spring-aop 模块, spring 实现 aspectj 借鉴了 aspectj 的语法, 因此需要再引入一个依赖:

    // AOP 支持
    compile group: 'org.aspectj', name: 'aspectjweaver', version: '1.9.2'

启用 Aspect,添加注解 @EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true),proxyTargetClass 默认为 false 使用 JDK 代理, true 表示使用 CGLIB 代理,exposeProxy 为 true 代表暴露 AopContext

package top.waterlaw.aspectj;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@ComponentScan("top.waterlaw.aspectj")
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
public class AppConfig {
    //- @EnableAspectJAutoProxy 启用 AspectJ 需要下载单独的 jar 包
}

定义一个切面

package top.waterlaw.aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class MyAspectJ {

    @Pointcut("@annotation(top.waterlaw.aspectj.MyApp)")
    public void pointCut() {
    }

//  @After("pointCut()")
//  public void advice() {
//      // advice 切入的时机
//      System.out.println("AOP before");
//  }
//
//  @Around("pointCut()")
//  public void around(JoinPoint pjp) {
//      System.out.println("AOP before");
//  }

    @Around("pointCut()")
    public void around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("aop before");
        pjp.getArgs();
        pjp.proceed();
        System.out.println("aop after");
    }
}

MyApp 注解

package top.waterlaw.aspectj;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface MyApp {
}

定义一个 Bean

package top.waterlaw.aspectj;

import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component("c")
public class CityService implements L {

    @Autowired
    CityService2 cityService2;

    public CityService(){
        System.out.println("init CityService..");
    }

    @Override
    @MyApp
    public void query() {
        System.out.println("query db--------");
        ((CityService)AopContext.currentProxy()).query1("query ...");
    }

    @Override
    @MyApp
    public void query1(String s) {
        System.out.println("s is "+s+"----------");
    }
}

被切点切到的方法使用 AopContext.currentProxy() 去运行,

测试下:

package top.waterlaw.aspectj;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {
    /**
     * 把类扫描出来
     * 把 bean 实例化
     */
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext =
                new AnnotationConfigApplicationContext(AppConfig.class);
        CityService cityService = (CityService)                 annotationConfigApplicationContext.getBean("c");
        cityService.query();
    }
}

结果如下:

十二月 13, 2019 4:31:17 上午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@a09ee92: 

startup date [Fri Dec 13 04:31:17 CST 2019]; root of context hierarchy
init CityService..
init CityService2
aop before
query db--------
aop before
s is query ...----------
aop after
aop after

其他博客

Spring 源码解析 – AnnotationConfigApplicationContext 容器创建过程

发表评论

评论内容
 

评论列表, 共 0 条评论