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.
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
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
下面的代码中的 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 的生命周期
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
发表评论
评论列表, 共 0 条评论