深入剖析:手写Spring源码的精简版解析与实现(附GitHub链接)
引出问题
- 原生 Spring 如何实现依赖注入和 singleton、prototype
- 原生 Spring 如何实现 BeanPostProcessor
- 原生 Spring 是如何实现 AOP
自己手动实现
一图胜千言

实现任务阶段 1- 编写自己 Spring 容器,实现扫描包, 得到bean 的class 对象

使用注解方式代替xml配置方式, 使用xml配置只要使用dom4j
解析技术就行, 道理一样的
如何创建 普通Maven项目

我的目录结构是
└─com
└─hspedu
└─Spring
│ AppMain.java 测试类
│
├─Annotation 参考原生实现
│ AfterReturning.java
│ Aspect.java
│ Autowired.java
│ Before.java
│ Component.java
│ ComponentScan.java
│ Scope.java
│
├─component
│ Car.java
│ HspBeanPostProcessor.java
│ MonsterDAO.java
│ MonsterService.java
│ SmartAnimal.java
│ SmartAnimalAspect.java
│ SmartDog.java
│
├─ioc
│ BeanDefinition.java
│ HspSpringApplicationContext.java
│ HspSpringConfig.java
│
└─processor
BeanPostProcessor.java
InitializingBean.java
需要的依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.5</version>
</dependency>
</dependencies>
HspSpringApplicationContext.java
非常重要的类, 先看其中的一个方法
public void beanDefinitionByScan(Class configClass) {
// 1. 拿到配置类上拿到的注解
ComponentScan componentScan = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
// 要扫描包的路径 com.hspedu.Spring.Annotation
String path = componentScan.value();
// System.out.println("path = " + path);
// com/hspedu/Spring/Annotation 路径
// 1. 找到类的加载器 --> APP类加载器
ClassLoader classLoader = HspSpringApplicationContext.class.getClassLoader();
path = path.replaceAll("\\.", "/");
// 2. 通过类的加载器, 获得扫描包的资源url
URL resource = classLoader.getResource(path);
// 3. 将要加载的资源(.class)路径进行遍历 io知识
File file = new File(resource.getFile());
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
String absolutePath = f.getAbsolutePath();
if (!absolutePath.endsWith(".class")) {
// 如果不是以.class结尾的就不进行下面的操作
return;
}
// 反射需要 的是 com.hspedu.Spring.component.MyComponent
// 获取到类名 类似于 MyComponent
String className = absolutePath.substring(absolutePath.lastIndexOf("\\") + 1, absolutePath.lastIndexOf(".class"));
// 反射需要的是 全类名
String classFullName = path.replaceAll("/", ".") + "." + className;
}
}
}
需要被扫描的配置类 HspSpringConfig.java
import com.hspedu.Spring.Annotation.ComponentScan;
/**
* ClassName: HspSpringConfig
* Package: com.hspedu.Spring.Annotation
*
* @Author: leikooo
* @Creat: 2023/5/29 - 12:02
* @Description: 模拟原生spring容器配置文件(beans.xml)
*/
@ComponentScan(value = "com.hspedu.Spring.component")
public class HspSpringConfig {
}
实现任务阶段 2- 扫描将 bean 信息封装到 BeanDefinition 对象,并放入到Map
BeanDefinition.java
用于记录Bean的信息 class反射全路径 + 是否是单例
/**
* ClassName: BeanDefinition
* Package: com.hspedu.Spring.ioc
*
* @Author: leikooo
* @Creat: 2023/5/29 - 17:05
* @Description: 用于记录Bean的信息 class反射全路径 + 是否是单例
*/
public class BeanDefinition {
private String scope;
public Class clazz;
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public Class getClazz() {
return clazz;
}
public void setClazz(Class clazz) {
this.clazz = clazz;
}
}
HspSpringApplicationContext.java
package com.hspedu.Spring.ioc;
import com.hspedu.Spring.Annotation.Autowired;
import com.hspedu.Spring.Annotation.Component;
import com.hspedu.Spring.Annotation.ComponentScan;
import com.hspedu.Spring.Annotation.Scope;
import com.hspedu.Spring.component.MonsterDAO;
import com.hspedu.Spring.processor.BeanPostProcessor;
import com.hspedu.Spring.processor.InitializingBean;
import org.apache.commons.lang.StringUtils;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
/**
* ClassName: HspSpringApplicationContext
* Package: com.hspedu.Spring.ioc
*
* @Author: leikooo
* @Creat: 2023/5/29 - 16:39
* @Description:
*/
public class HspSpringApplicationContext {
// 使用反射需要Class类
private Class configClass;
// 定义一个属性 BeanDefinitionMap -> 存放BeanDefinition
private final ConcurrentHashMap<String, BeanDefinition> BeanDefinitionMap = new ConcurrentHashMap<>();
// 定义一个SingletonObjects -> 存放单例对象
private final ConcurrentHashMap<String, Object> SingletonObjects = new ConcurrentHashMap<>();
public HspSpringApplicationContext(Class configClass) {
beanDefinitionByScan(configClass);
Enumeration<String> keys = BeanDefinitionMap.keys();
while (keys.hasMoreElements()) {
// 得到beanName
String beanName = keys.nextElement();
// 通过beanName 得到对应的beanDefinition对象
BeanDefinition beanDefinition = BeanDefinitionMap.get(beanName);
// 判断 是单例还是多例
String scope = beanDefinition.getScope();
if ("singleton".equals(scope)) {
// 单例直接创建
Object bean = createBean(beanName, beanDefinition);
if (!SingletonObjects.containsKey(beanName)) {
// 如果已经创建了, 就不用再进行创建了
SingletonObjects.put(beanName, bean);
}
}
}
}
/**
* 该方法完成对指定包的扫描, 并将Bean信息封装到 BeanDefinition对象, 并放入到Map之中
*
* @param configClass 配置对象
*/
public void beanDefinitionByScan(Class configClass) {
// 1. 拿到配置类上拿到的注解
ComponentScan componentScan = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
// 要扫描包的路径 com.hspedu.Spring.Annotation
String path = componentScan.value();
// System.out.println("path = " + path);
// com/hspedu/Spring/Annotation 路径
// 1. 找到类的加载器 --> APP类加载器
ClassLoader classLoader = HspSpringApplicationContext.class.getClassLoader();
path = path.replaceAll("\\.", "/");
// 2. 通过类的加载器, 获得扫描包的资源url
URL resource = classLoader.getResource(path);
// 3. 将要加载的资源(.class)路径进行遍历 io知识
File file = new File(resource.getFile());
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
String absolutePath = f.getAbsolutePath();
if (!absolutePath.endsWith(".class")) {
// 如果不是以.class结尾的就不进行下面的操作
return;
}
// 反射需要 的是 com.hspedu.Spring.component.MyComponent
// 获取到类名 类似于 MyComponent
String className = absolutePath.substring(absolutePath.lastIndexOf("\\") + 1, absolutePath.lastIndexOf(".class"));
// 反射需要的是 全类名
String classFullName = path.replaceAll("/", ".") + "." + className;
try {
Class<?> clazz = classLoader.loadClass(classFullName);
if (clazz.isAnnotationPresent(Component.class)) {
// 获得注解上面的value属性, 作为key
if (clazz.isAnnotationPresent(Component.class)) {
// 如果该类使用了@Component
// 1. 得到 Component 注解
Component componentAnnotation = clazz.getDeclaredAnnotation(Component.class);
// 2. 的配置value值, 疑问 如果程序员没有配置value
String beanName = componentAnnotation.value();
if ("".equals(beanName)) {
// 如果没有指定值, 那么直接首字母小写
// 注意这里的 StringUtils 是 org.apache.commons.lang 目录下面的
beanName = StringUtils.uncapitalize(className);
String name = clazz.getName();
// System.out.println("name = " + name);
}
// 3. 这里把bean信息封装到 BeanDefinitionMap
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setClazz(clazz);
// 4. 获取到Scope的值
if (clazz.isAnnotationPresent(Scope.class)) {
Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);
String value = scopeAnnotation.value();
if ("".equals(value)) {
value = "singleton";
}
beanDefinition.setScope(value);
} else {
// 没有配置scope就获取其他配置的值
beanDefinition.setScope("singleton");
}
// 5. 将beanDefinition 放到Map
BeanDefinitionMap.put(beanName, beanDefinition);
}
} else {
System.out.println("这不是一个SpringBean bean = " + clazz + " 类名 " + className);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
}

解析:
这两个Map集合非常重要
- 定义一个属性
BeanDefinitionMap
-> 存放BeanDefinition , 这个是存放类的信息 - 定义一个
SingletonObjects
-> 存放单例对象, 如果是单例对象那么直接创建放到map之中
实现任务阶段 3- 初始化 bean 单例池,并完成 getBean 方法, createBean 方法
完成 getBean()
方法
有三种情况
- 如果这个bean不存在就抛异常
- 如果这个bean存在, 但是单例池中没有这个对象 --> 调用creatBean()
- 如果这个bean存在, 单例池中有对象 --> 从单例池中直接取出
// creatBean() 方法非常重要很多东西都在其中
public Object creatBean(String beanName, BeanDefinition beanDefinition) {
Object bean = null;
try {
bean = beanDefinition.getClazz().getDeclaredConstructor().newInstance();
System.out.println("=======初始化======" + bean);
} catch (Exception e) {
throw new RuntimeException(e);
}
return bean;
}
// 获取bean
public Object getBean(String beanName) {
if (!beanDefinitionMap.containsKey(beanName)) {
throw new RuntimeException("NO SUCH BEAN");
}
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if ("singleton".equals(beanDefinition.getScope())) {
return SingletonMap.get(beanName);
} else {
// 如果单例池里面没有对应的对象, 那么创建
return creatBean(beanName, beanDefinition);
}
}
实现任务阶段 4- 完成依赖注入
在 creatBean()
方法实现依赖注入就非常合适, 因为不管是 singleton
还是 prototype
都需要使用这个方法, 而且这时候对象不会放到单例池
之中 ( 或者返回 )
public Object creatBean(String beanName, BeanDefinition beanDefinition) {
Object bean = null;
try {
bean = beanDefinition.getClazz().getDeclaredConstructor().newInstance();
// 这里实现自动装配
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
// 如果某一个属性是标识了 @Autowired 注解
String fieldName = field.getName();
field.setAccessible(true);
Object o = getBean(fieldName);
// 第一个参数是 对象
field.set(bean, o);
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return bean;
}
实现任务阶段 5- bean 后置处理器实现和初始化方法
容器中有一个常用的方法是, 根据该类是否实现了某个接口, 来判断是否要执行某个逻辑, 这个其实就是Java基础的接口编程实际运用
这个修改的地方就不止 creatBean()
这个方法了, 还有需要在 beanDefinitionByScan()
进行修改
这里为了简化, 专门为了 实现接口的类创建了一个List, 便于以后使用. 但是底层还是在 单例池中 【如果是那样的话太过复杂】
import com.hspedu.Spring.Annotation.Autowired;
import com.hspedu.Spring.Annotation.Component;
import com.hspedu.Spring.Annotation.ComponentScan;
import com.hspedu.Spring.Annotation.Scope;
import com.hspedu.Spring.processor.BeanPostProcessor;
import com.hspedu.Spring.processor.InitializingBean;
import org.apache.commons.lang.StringUtils;
import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* ClassName: HspSpringApplicationContext
* Package: com.hspedu.Spring.ioc
*
* @Author: leikooo
* @Creat: 2023/6/1 - 12:12
* @Description:
*/
public class HspSpringApplicationContext {
private Class configure;
private final ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
// 注意这里是object
private final ConcurrentHashMap<String, Object> SingletonMap = new ConcurrentHashMap<String, Object>();
private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();
public HspSpringApplicationContext(Class configure) {
beanDefinitionByScan(configure);
// 拿到已经整好的定义bean
Enumeration<String> keys = beanDefinitionMap.keys();
while (keys.hasMoreElements()) {
String beanName = keys.nextElement();
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if ("singleton".equals(beanDefinition.getScope())) {
// 如果是单例直接创建, 放到单例池
SingletonMap.put(beanName, creatBean(beanName, beanDefinition));
}
}
}
public Object creatBean(String beanName, BeanDefinition beanDefinition) {
Object bean = null;
try {
bean = beanDefinition.getClazz().getDeclaredConstructor().newInstance();
// 这里实现自动装配
Field[] fields = bean.getClass().getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(Autowired.class)) {
// 如果某一个属性是标识了 @Autowired 注解
String fieldName = field.getName();
field.setAccessible(true);
Object o = getBean(fieldName);
field.set(bean, o);
}
}
System.out.println("=======初始化======" + bean);
// 实现后置通知
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
Object o = beanPostProcessor.postProcessBeforeInitialization(bean, beanName);
bean = o != null ? o : bean;
}
// 实现初始化方法
if (InitializingBean.class.isAssignableFrom(bean.getClass())) {
((InitializingBean) bean).afterPropertiesSet();
}
for (BeanPostProcessor beanPostProcessor : beanPostProcessors) {
Object o = beanPostProcessor.postProcessAfterInitialization(bean, beanName);
bean = o != null ? o : bean;
}
System.out.println("---------------------");
} catch (Exception e) {
throw new RuntimeException(e);
}
return bean;
}
// 获取bean
public Object getBean(String beanName) {
if (!beanDefinitionMap.containsKey(beanName)) {
throw new RuntimeException("NO SUCH BEAN");
}
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if ("singleton".equals(beanDefinition.getScope())) {
return SingletonMap.get(beanName);
} else {
return creatBean(beanName, beanDefinition);
}
}
// 扫描装配
public void beanDefinitionByScan(Class configure) {
this.configure = configure;
if ((configure != null) && configure.isAnnotationPresent(ComponentScan.class)) {
ComponentScan componentScan = (ComponentScan) configure.getDeclaredAnnotation(ComponentScan.class);
String path = componentScan.value();
// System.out.println("path = " + path);
// com/hspedu/Spring/Annotation 路径
// 1. 找到类的加载器 --> APP类加载器
ClassLoader classLoader = HspSpringApplicationContext.class.getClassLoader();
path = path.replaceAll("\\.", "/");
// 2. 通过类的加载器, 获得扫描包的资源url
URL resource = classLoader.getResource(path);
// 3. 将要加载的资源(.class)路径进行遍历 io知识
File file = new File(resource.getFile());
if (file.isDirectory()) {
File[] files = file.listFiles();
for (File f : files) {
String absolutePath = f.getAbsolutePath();
if (!absolutePath.endsWith(".class")) {
// 如果不是以.class结尾的就不进行下面的操作
return;
}
// 反射需要 的是 com.hspedu.Spring.component.MyComponent
// 获取到类名 类似于 MyComponent
String className = absolutePath.substring(absolutePath.lastIndexOf("\\") + 1, absolutePath.lastIndexOf(".class"));
// 反射需要的是 全类名
String classFullName = path.replaceAll("/", ".") + "." + className;
// 造对象, 放到单例池
try {
Class<?> clazz = Class.forName(classFullName);
if (clazz.isAnnotationPresent(Component.class)) {
String beanName = clazz.getDeclaredAnnotation(Component.class).value();
if ("".equals(beanName)) {
// 如果没写有指定beanName那么就应类名小写代替
beanName = StringUtils.uncapitalize(className);
}
// 这里判断是不是后置处理器
if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
// 如果实现了 BeanPostProcessor 接口
beanPostProcessors.add((BeanPostProcessor) clazz.getDeclaredConstructor().newInstance());
// 就不需要在放到 beanDefinitionMap 里面
continue;
}
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setClazz(clazz);
if (clazz.isAnnotationPresent(Scope.class)) {
String scope = clazz.getDeclaredAnnotation(Scope.class).value();
if ("".equals(scope)) {
// 没有指定默认singleton
scope = "singleton";
}
beanDefinition.setScope(scope);
} else {
beanDefinition.setScope("singleton");
}
beanDefinitionMap.put(beanName, beanDefinition);
}
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException |
IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
}
}
}
}
BeanPostProcessor
接口
只要实现这个接口, 就可以实现调用 后置处理器
public interface BeanPostProcessor {
/**
* 该方法会在bean的初始化方法后调用
*
* @param bean
* @param beanName
* @return
*/
default Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
/**
* 该方法在bean的初始化方法之前调用
*
* @param bean
* @param beanName
* @return
*/
default Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
}
InitializingBean
接口
只要实现这个接口就可以实现bean的初始化方法
/**
* ClassName: InitializingBean
* Package: com.hspedu.Spring.processor
*
* @Author: leikooo
* @Creat: 2023/5/30 - 17:47
* @Description: 我们自己写的
* 1. 我们根据原生的Spring, 定义了InitializingBean
* 2. 该接口中有一个方法 void afterPropertiesSet() throws Exception;
* 3. 这个方法会在setter方法之后执行, 就相当于原来配置的初始化方法
* 4. 当一个Bean实现这个接口之后, 就实现了afterPropertiesSet, 那么这个方法方法就实现了初始化方法
*/
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
/**
* ClassName: HspBeanPostProcessor
* Package: com.hspedu.Spring.component
*
* @Author: leikooo
* @Creat: 2023/6/2 - 17:49
* @Description:
*/
@Component
public class HspBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println(bean + "的后置通知 postProcessBeforeInitialization");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println(bean + "的后置通知 postProcessAfterInitialization");
return bean;
}
}
实现任务阶段 6- AOP 机制实现
AOP的实现依赖于 后置处理器

其实就是在后置处理器进行 动态代理
返回代理对象, 就实现了AOP
/**
* ClassName: HspBeanPostProcessor
* Package: com.hspedu.Spring.component
*
* @Author: leikooo
* @Creat: 2023/6/2 - 17:49
* @Description:
*/
@Component
public class HspBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println(bean + "的后置通知 postProcessBeforeInitialization");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println(bean + "的后置通知 postProcessAfterInitialization");
// 这里AOP机制
if (bean instanceof SmartAnimal) {
// 如果实现了 接口
return Proxy.newProxyInstance(
bean.getClass().getClassLoader(),
bean.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj = null;
if ("getSum".equals(method.getName())) {
SmartAnimalAspect.beforeLog();
obj = method.invoke(bean, args);
SmartAnimalAspect.afterLog();
} else {
// 如果该方法没有加注解被标识那么还是执行原来的方法
obj = method.invoke(bean, args);
}
return obj;
}
}
);
}
return bean;
}
}
实现效果

补充内容
简单分析AOP和BeanPostProcessor的关系
首先 AOP实现Spring可以通过给类加入注解 @EnableAspectJAutoProxy
来实现





AnnotationAwareAspectJAutoProxyCreator.class
的类图

总结:
- AOP 底层是基于
BeanPostProcessor
机制的. - 即在 Bean 创建好后,根据是否需要
AOP 处理
,决定返回代理对象
,还是原生Bean
- 在返回代理对象时,就可以根据要代理的类和方法来返回
- 其实这个机制并不难,本质就是在 BeanPostProcessor 机制+ 动态代理技术5)
类的加载器
java 的类加载器 3 种
Bootstrap
类加载器--------------对应路径jre/lib
Ext
类加载器--------------------对应路径jre/lib/ext
App
类加载器-------------------对应路径classpath
classpath
这个是一系列路径

转载自:https://juejin.cn/post/7242119057913954359