手写简易Spring框架
手写简易Spring框架:从零实现IoC容器
在这篇博客中,我将分享如何从零开始实现一个简易的Spring框架核心功能,包括IoC容器、依赖注入和组件扫描等核心特性。
项目结构概述
这个简易Spring框架主要包含以下几个核心包:
my.self.spring.annotation
:自定义注解my.self.spring.BeanFactory
:Bean工厂实现my.self.spring.ApplicationContext
:应用上下文实现my.self.spring.Definition
:Bean定义相关类my.self.spring.proxy
:代理相关实现
核心功能实现
1. 注解定义
首先定义了Spring中常见的几个核心注解:
// 组件扫描注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {String[] value();
}// 组件注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {String value() default "";
}// 自动装配注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
}// 作用域注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {String value() default "singleton";
}
2. Bean工厂实现
DefaultListableBeanFactory
是整个框架的核心,负责Bean的创建、管理和依赖注入:
package my.self.spring.BeanFactory;import my.self.spring.Definition.AnnotateBeanDefinition;
import my.self.spring.Definition.AnnotateGenericBeanDefinition;
import my.self.spring.Definition.BeanDefinition;
import my.self.spring.Definition.BeanDefinitionRegistry;
import my.self.spring.Function.ObjectFactory;
import my.self.spring.annotation.*;
import my.self.spring.proxy.JdkProxyBeanPostProcess;
import my.self.spring.uitls.StringUtils;import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;import static my.self.spring.emun.ScopeType.SINGLETON;/*** @Description:* @author: zh* @Create : 2025/6/26* @Project_name : SelfsSpring* @Version :**/
public class DefaultListableBeanFactory implements BeanFactory, BeanDefinitionRegistry {private final Map<String, AnnotateBeanDefinition> definitionMap= new ConcurrentHashMap<>(256);/*** Bean name 集合*/private final List<String> beanDefinitionNames = new ArrayList<>();/*** 一级缓存*/private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);/*** 二级缓存*/private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(256);//三级缓存private final Map<String, ObjectFactory> singletonFactories = new ConcurrentHashMap<>(256);//三级缓存的循环对象private final Set<String> singletonCurrentlyInCreation =new HashSet<>(256);/*** 获取bean根据BeanName** @param beanName* @return*/public Object getBean(String beanName) {return doGetBean(beanName);}private Object doGetBean(String beanName) {Object bean = getSingletonObjects(beanName);if(bean != null){return bean;}//获取BeanDefinitionAnnotateGenericBeanDefinition annotateBeanDefinition = (AnnotateGenericBeanDefinition) definitionMap.get(beanName);//实例化beanbean = createBean(beanName,annotateBeanDefinition.getClazz());if (annotateBeanDefinition.getScope().equals(SINGLETON)) {//是单例的则会添加到singletonObjects中singletonObjects.put(beanName,bean);}return bean;}private Object getSingletonObjects(String beanName) {Object singleton = singletonObjects.get(beanName);if(singleton == null&& singletonCurrentlyInCreation.contains(beanName)) {singleton = earlySingletonObjects.get(beanName);if(singleton == null){ObjectFactory objectFactory = singletonFactories.get(beanName);if(objectFactory != null){try {//取出半实例化对象singleton = objectFactory.getObject();} catch (Exception e) {throw new RuntimeException(e);}}}}return singleton;}/*** 创建bean** @param beanName* @param clazz* @return*/private Object createBean(String beanName, Class<?> clazz) {try {if(!singletonCurrentlyInCreation.contains(beanName)){singletonCurrentlyInCreation.add(beanName);}//实例化Object bean = clazz.newInstance();earlySingletonObjects.put(beanName,bean);if(singletonCurrentlyInCreation.contains(beanName)){singletonFactories.put(beanName,()->new JdkProxyBeanPostProcess().postProcessBeforeInitialization(earlySingletonObjects.get(beanName),beanName));}//属性注入for(Field field:clazz.getDeclaredFields()){if(field.isAnnotationPresent(Autowired.class)){field.setAccessible(true);Object fieldbean = getBean(field.getName());field.set(bean,fieldbean);}}singletonCurrentlyInCreation.remove(beanName);singletonFactories.remove(beanName);earlySingletonObjects.remove(beanName);return bean;} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);}}/*** 通过beanClazz获取Bean的clazz** @param beanClass* @return*/public Object getBean(Class<?> beanClass) {return this.getBean(beanClass.getName());}/*** 扫描bean包下的定义** @param beanName* @param beanDefinition*/public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {Class<?> clazz = null;//根据对应的类型去判断是什么方式注入的if (beanDefinition instanceof AnnotateBeanDefinition) {//注解方式注入//找到对应的实现类if (beanDefinition instanceof AnnotateGenericBeanDefinition) {AnnotateGenericBeanDefinition annotateGenericBeanDefinition = (AnnotateGenericBeanDefinition) beanDefinition;definitionMap.put(beanName, annotateGenericBeanDefinition);}}}/*** 扫描注解路径下的全部类--并将其将入初始化工厂中*/public void doScan() {try {//目前只扫描对应包下的组件Set<String> strings = definitionMap.keySet();for (String beanName : strings) {AnnotateGenericBeanDefinition annotateBeanDefinition = (AnnotateGenericBeanDefinition) definitionMap.get(beanName);if (annotateBeanDefinition.getClazz().isAnnotationPresent(ComponentScan.class)) {ComponentScan componentScan = annotateBeanDefinition.getClazz().getAnnotation(ComponentScan.class);String[] packageNames = componentScan.value();for (String packageName:packageNames) {//扫描包下的所有类URL url = this.getClass().getClassLoader().getResource(packageName.replaceAll("\\.", "/"));File file = new File(url.getFile());if (file.isDirectory()) {for (File f : file.listFiles()) {//xxx.xxx.UserServiceClass<?> clazz = this.getClass().getClassLoader().loadClass(packageName.concat(".").concat(f.getName().split("\\.")[0]));String[] split = clazz.getName().split("\\.");String className = split[split.length - 1];if (clazz.isAnnotationPresent(Component.class)) {className = clazz.getAnnotation(Component.class).value().equals("") ?className : clazz.getAnnotation(Component.class).value();className = StringUtils.parserBeanName(className);AnnotateGenericBeanDefinition annotationDefinition = new AnnotateGenericBeanDefinition();annotationDefinition.setClazz(clazz);//将类加入工厂中if (clazz.isAnnotationPresent(Scope.class) && clazz.getAnnotation(Scope.class).value() != null) {annotationDefinition.setScope(clazz.getAnnotation(Scope.class).value());} else {annotationDefinition.setScope(SINGLETON);}definitionMap.put(className, annotationDefinition);beanDefinitionNames.add(className);}}}}}}} catch(Exception e){throw new RuntimeException(e);}}/*** 创建单例方法*/public void preInstantiateSingletons() {//防止在创建单例的时候,单例还没有创建完成List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);for (String beanName : beanNames){getBean(beanName);}}
}
3. 应用上下文
AnnotationConfigApplicationContext
是面向用户的入口类,提供了基于注解的配置方式:
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements BeanDefinitionRegistry {private AnnotateBeanDefinitionReader reader;public AnnotationConfigApplicationContext(Class<?>... componentClass) {this();register(componentClass);super.refresh();}private void register(Class<?>... componentClass) {for (Class<?> aClass : componentClass) {this.reader.register(aClass);}}
}
4. 组件扫描
组件扫描是自动发现和注册Bean的关键功能:
public void doScan() {try {Set<String> strings = definitionMap.keySet();for (String beanName : strings) {AnnotateGenericBeanDefinition beanDefinition = (AnnotateGenericBeanDefinition) definitionMap.get(beanName);if (beanDefinition.getClazz().isAnnotationPresent(ComponentScan.class)) {ComponentScan componentScan = beanDefinition.getClazz().getAnnotation(ComponentScan.class);for (String packageName : componentScan.value()) {// 扫描包路径下的所有类URL url = this.getClass().getClassLoader().getResource(packageName.replaceAll("\\.", "/"));File file = new File(url.getFile());if (file.isDirectory()) {for (File f : file.listFiles()) {Class<?> clazz = this.getClass().getClassLoader().loadClass(packageName.concat(".").concat(f.getName().split("\\.")[0]));if (clazz.isAnnotationPresent(Component.class)) {// 注册Bean定义String className = StringUtils.parserBeanName(clazz.getAnnotation(Component.class).value().equals("") ?clazz.getSimpleName() : clazz.getAnnotation(Component.class).value());AnnotateGenericBeanDefinition annotationDefinition = new AnnotateGenericBeanDefinition();annotationDefinition.setClazz(clazz);annotationDefinition.setScope(clazz.isAnnotationPresent(Scope.class) ? clazz.getAnnotation(Scope.class).value() : SINGLETON);definitionMap.put(className, annotationDefinition);beanDefinitionNames.add(className);}}}}}}} catch(Exception e) {throw new RuntimeException(e);}
}
5.动态代理
函数式接口
package my.self.spring.Function;import jdk.nashorn.internal.objects.annotations.Function;/*** @Description:* @author: zh* @Create : 2025/7/24* @Project_name : SelfsSpring* @Version :**/
@FunctionalInterface
public interface ObjectFactory<T> {T getObject() throws Exception;}
动态代理接口
package my.self.spring.proxy;public interface JDKService {public void execute();
}
动态代理实现类
package my.self.spring.proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;/*** @Description:* @author: zh JDk动态代理类* @Create : 2025/7/24* @Project_name : SelfsSpring* @Version :**/
public class JdkDynamicProxy<T> implements InvocationHandler {private T target;public JdkDynamicProxy(T target) {this.target = target;}public <T> T getProxy(){return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {return method.invoke(target, args);}
}
动态代理handler
package my.self.spring.proxy;/*** @Description:* @author: zh* @Create : 2025/7/24* @Project_name : SelfsSpring* @Version :**/
public class JdkProxyBeanPostProcess {public Object postProcessBeforeInitialization(Object bean, String beanName) {if(bean instanceof JDKService){System.out.println(beanName+" instanceof JDKService");bean = new JdkDynamicProxy(bean).getProxy();}return bean;}
}
6.工具类
package my.self.spring.uitls;/*** @Description:* @author: zh* @Create : 2025/7/24* @Project_name : SelfsSpring* @Version :**/
public class StringUtils {public static String parserBeanName(String beanName) {if(beanName == null || beanName.trim().length() == 0 || "".equals(beanName)){return beanName;}return beanName.substring(0,1).toLowerCase() + beanName.substring(1);}
}
使用示例
定义配置类:
@ComponentScan("my.self.test.bean")
public class AppConfig {
}
定义业务组件:
@Component
public class UserService {@Autowiredprivate OrderService orderService;public void execute() {System.out.println("UserService execute");}
}@Component
public class OrderService implements JDKService {@Autowiredprivate UserService userService;public void execute() {System.out.println("OrderService execute");}
}
启动应用:
public class SpringTest {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = (UserService) context.getBean("userService");OrderService orderService = (OrderService) context.getBean("orderService");userService.execute();orderService.execute();}
}
实现亮点
- 三级缓存解决循环依赖:通过singletonObjects、earlySingletonObjects和singletonFactories三级缓存机制解决了循环依赖问题。
- 基于注解的配置:支持@ComponentScan、@Component、@Autowired等常用注解。
- 作用域支持:通过@Scope注解支持单例和原型作用域。
- 简洁的API设计:模仿Spring的设计,提供了简单易用的API接口。
总结
这个简易Spring框架实现了IoC容器的核心功能,包括:
- 组件扫描与自动注册
- 依赖注入
- 循环依赖处理
- 单例管理
虽然功能相比完整的Spring框架简单很多,但核心思想是一致的。通过这个实现,可以更好地理解Spring框架的内部工作原理。