> 文档中心 > 手写模拟Spring

手写模拟Spring


主要方向

  • 了解Spring底层源码的启动过程
  • 了解BeanDefinition、BeanPostProcessor的概念
  • 了解Spring解析配置类等底层源码工作流程
  • 了解依赖注入、Aware回调等底层源码工作流程
  • 了解Spring AOP的底层源码工作流程

大致实现生命周期

  • 类通过无参构造实例化
  • 依赖注入
  • Aware接口回调
  • 初始化前: 实现BeanPostProcessor.postProcessBeforeInitialization
  • 初始化前: 调用@PostConstruct注解的方法
  • 初始化: 实现InitializingBean.afterPropertiesSet
  • 初始化后: 实现BeanPostProcessor.postProcessAfterInitialization
  • 初始化后: BeanPostProcessor(Aop–>代理对象)
  • Bean对象

手写模拟Spring

前提准备

@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface Component {    String name() default "";}
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface ComponentScan {    String[] basePackages() default {};}
@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD, ElementType.METHOD})public @interface Autowired {}
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface Scope {    String value() default "singleton";}
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface PostConstruct {}
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface Value {    String value() default "";}
public class BeanDefinition {private Class<?> clazz;/** * 作用域: singleton * prototype */private String scope;public Class<?> getClazz() {return clazz;}public void setClazz(Class<?> clazz) {this.clazz = clazz;}public String getScope() {return scope;}public void setScope(String scope) {this.scope = scope;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;BeanDefinition that = (BeanDefinition) o;return Objects.equals(clazz, that.clazz) && Objects.equals(scope, that.scope);}@Overridepublic int hashCode() {return Objects.hash(clazz, scope);}}
public interface BeanPostProcessor {    /**     * 该方法在bean实例化完毕(且已经注入完毕),在afterPropertiesSet或自定义init方法执行之前     */    default Object postProcessBeforeInitialization(Object bean, String beanName) { return bean;    }    /**     * 在afterPropertiesSet或自定义init方法执行之后     */    default Object postProcessAfterInitialization(Object bean, String beanName) { return bean;    }}
public interface InitializingBean {    void afterPropertiesSet();}
public interface BeanNameAware {    void setBeanName(String beanName);}

实现包扫描逻辑

public class AnnotationConfigApplicationContext {/** * 配置类 */private final Class<?> configClass;/** * beanName,BeanDefinition * 专门用来存储扫描到的BeanDefinition */private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);/** * 继承了BeanPostProcessor的类 */private final List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();/** * 扫描到的class文件 */private final List<File> scannedFiles = new ArrayList<>();/** * 单例池 */private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);public AnnotationConfigApplicationContext(Class<?> configClass) {this.configClass = configClass; // 进行包扫描scan(configClass);}/** * 扫描包路径下加了@Component注解的放到beanDefinitionMap */private void scan(Class<?> configClass) {// 如果配置类加上了@ComponentScanif (configClass.isAnnotationPresent(ComponentScan.class)) {// 从注解上拿到需要扫描的包路径basePackagesComponentScan componentScan = configClass.getAnnotation(ComponentScan.class);String[] basePackages = componentScan.basePackages();// 遍历包路径,通过io去拿到所有class文件for (String basePackage : basePackages) {// 扫描包// 找到包路径下的所有class,解析class得到BeanDefinitionscanCandidateComponents(basePackage);}}}/** * 扫描包路径下的class文件并且解析,如果有@Component就进行解析成BeanDefinition */private void scanCandidateComponents(String basePackage) {// 获取包路径下的文件// 判断当前是否是目录,如果是目录就递归去获取class文件,这里我们需要把这些扫描到的class文件保存下来listPackageFiles(getPackageFile(basePackage));// 遍历扫描到的文件找出class文件,判断class文件中有没有@Component,如果有就看是单例还是原型的composeBeanDefinition(scannedFiles);}/** * 构建BeanDefinition */private void composeBeanDefinition(List<File> scannedFiles) {// 遍历扫描到的文件找出class文件for (File f : scannedFiles) {// 获取f的绝对路径String absolutePath = f.getAbsolutePath();// 判断是否是class文件if (absolutePath.contains(".class")) {// 根据不同操作系统,获取指定的二进制名称String binaryName = getBinaryName(absolutePath);try {// 通过当前类加载器加载二进制名称Class<?> clazz = this.getClass().getClassLoader().loadClass(binaryName);// 判断该类是否有@Componentif (clazz.isAnnotationPresent(Component.class)) {// 这里我们要考虑判断有没有继承BeanPostProcessor,如果有那么就把这些类放到beanPostProcessorList里缓存下来if (BeanPostProcessor.class.isAssignableFrom(clazz)) {BeanPostProcessor beanPostProcessor = (BeanPostProcessor) clazz.getConstructor().newInstance();beanPostProcessorList.add(beanPostProcessor);}// 拿到当前类的@Component的注解信息beanNameComponent component = clazz.getAnnotation(Component.class);String beanName = component.name();// 如果beanName不填写,就默认用类名生成小写if ("".equals(beanName)) {beanName = Introspector.decapitalize(clazz.getSimpleName());}BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setClazz(clazz);// 判断bean是否是单例的,如果有值就按照传递的否则按照单例默认值进行if (clazz.isAnnotationPresent(Scope.class)) {Scope scope = clazz.getAnnotation(Scope.class);beanDefinition.setScope(scope.value());} else {// 默认使用singletonbeanDefinition.setScope("singleton");}// 将beanDefinition放入beanDefinitionMapbeanDefinitionMap.put(beanName, beanDefinition);}} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {e.printStackTrace();}}}}   /** * 根据不同操作系统,获取指定的二进制名称 */private String getBinaryName(String absolutePath, boolean isMaven) {String os = System.getProperty("os.name");String path;if (isMaven) {if (os.startsWith("Windows")) {path = "target\\classes";absolutePath = absolutePath.substring(absolutePath.indexOf(path) + path.length() + 1, absolutePath.indexOf(".class"));absolutePath = absolutePath.replace("\\", ".");} else {path = "target/classes";absolutePath = absolutePath.substring(absolutePath.indexOf(path) + path.length() + 1, absolutePath.indexOf(".class"));absolutePath = absolutePath.replace("/", ".");}} else {// gradleif (os.startsWith("Windows")) {path = "out\\production\\classes";absolutePath = absolutePath.substring(absolutePath.indexOf(path) + path.length() + 1, absolutePath.indexOf(".class"));absolutePath = absolutePath.replace("\\", ".");} else {path = "out/production/classes";absolutePath = absolutePath.substring(absolutePath.indexOf(path) + path.length() + 1, absolutePath.indexOf(".class"));absolutePath = absolutePath.replace("/", ".");}}return absolutePath;}/** * 列举出file下的所有class文件 */private void listPackageFiles(File file) {// 判断当前是否是目录if (file.isDirectory()) {File[] files = file.listFiles();assert files != null;if (files.length == 0) {return;}for (File f : files) {scannedFiles.add(f);// 判断当前是否是目录if (f.isDirectory()) {// 继续递归获取f下的class文件listPackageFiles(f);}}}}/** * 获取包路径下的文件 */private File getPackageFile(String basePackage) {// 这里想到我们指定的路径linc.cool,我们要转变成linc/cool,所以需要替换String path = basePackage.replace(".", "/");// 通过类加载器去获取path路径下的文件URL resource = this.getClass().getClassLoader().getResource(path);assert resource != null;return new File(resource.getFile());}}

实现getBean逻辑、注册Bean逻辑、相关生命周期

public class AnnotationConfigApplicationContext {/** * 配置类 */private final Class<?> configClass;/** * beanName,BeanDefinition * 专门用来存储扫描到的BeanDefinition */private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);/** * 继承了BeanPostProcessor的类 */private final List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();/** * 扫描到的class文件 */private final List<File> scannedFiles = new ArrayList<>();/** * 单例池 */private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);public AnnotationConfigApplicationContext(Class<?> configClass) {this.configClass = configClass;// 进行包扫描scan(configClass);// 注册单例beanDefinition到单例池registerBean();}/** * 扫描包路径下加了@Component注解的放到beanDefinitionMap */private void scan(Class<?> configClass) {// 如果配置类加上了@ComponentScanif (configClass.isAnnotationPresent(ComponentScan.class)) {// 从注解上拿到需要扫描的包路径basePackagesComponentScan componentScan = configClass.getAnnotation(ComponentScan.class);String[] basePackages = componentScan.basePackages();// 遍历包路径,通过io去拿到所有class文件for (String basePackage : basePackages) {// 扫描包// 找到包路径下的所有class,解析class得到BeanDefinitionscanCandidateComponents(basePackage);}}}/** * 扫描包路径下的class文件并且解析,如果有@Component就进行解析成BeanDefinition */private void scanCandidateComponents(String basePackage) {// 获取包路径下的文件// 判断当前是否是目录,如果是目录就递归去获取class文件,这里我们需要把这些扫描到的class文件保存下来listPackageFiles(getPackageFile(basePackage));// 遍历扫描到的文件找出class文件,判断class文件中有没有@Component,如果有就看是单例还是原型的composeBeanDefinition(scannedFiles);}/** * 构建BeanDefinition */private void composeBeanDefinition(List<File> scannedFiles) {// 遍历扫描到的文件找出class文件for (File f : scannedFiles) {// 获取f的绝对路径String absolutePath = f.getAbsolutePath();// 判断是否是class文件if (absolutePath.contains(".class")) {// 根据不同操作系统,获取指定的二进制名称String binaryName = getBinaryName(absolutePath, false);System.out.println(binaryName);try {// 通过当前类加载器加载二进制名称Class<?> clazz = this.getClass().getClassLoader().loadClass(binaryName);// 判断该类是否有@Componentif (clazz.isAnnotationPresent(Component.class)) {// 这里我们要考虑判断有没有继承BeanPostProcessor,如果有那么就把这些类放到beanPostProcessorList里缓存下来if (BeanPostProcessor.class.isAssignableFrom(clazz)) {BeanPostProcessor beanPostProcessor = (BeanPostProcessor) clazz.getConstructor().newInstance();beanPostProcessorList.add(beanPostProcessor);}// 拿到当前类的@Component的注解信息beanNameComponent component = clazz.getAnnotation(Component.class);String beanName = component.name();// 如果beanName不填写,就默认用类名生成小写if ("".equals(beanName)) {beanName = Introspector.decapitalize(clazz.getSimpleName());}BeanDefinition beanDefinition = new BeanDefinition();beanDefinition.setClazz(clazz);// 判断bean是否是单例的,如果有值就按照传递的否则按照单例默认值进行if (clazz.isAnnotationPresent(Scope.class)) {Scope scope = clazz.getAnnotation(Scope.class);beanDefinition.setScope(scope.value());} else {// 默认使用singletonbeanDefinition.setScope("singleton");}// 将beanDefinition放入beanDefinitionMapbeanDefinitionMap.put(beanName, beanDefinition);}} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {e.printStackTrace();}}}}/** * 根据不同操作系统,获取指定的二进制名称 */private String getBinaryName(String absolutePath, boolean isMaven) {String os = System.getProperty("os.name");String path;if (isMaven) {if (os.startsWith("Windows")) {path = "target\\classes";absolutePath = absolutePath.substring(absolutePath.indexOf(path) + path.length() + 1, absolutePath.indexOf(".class"));absolutePath = absolutePath.replace("\\", ".");} else {path = "target/classes";absolutePath = absolutePath.substring(absolutePath.indexOf(path) + path.length() + 1, absolutePath.indexOf(".class"));absolutePath = absolutePath.replace("/", ".");}} else {// gradleif (os.startsWith("Windows")) {path = "out\\production\\classes";absolutePath = absolutePath.substring(absolutePath.indexOf(path) + path.length() + 1, absolutePath.indexOf(".class"));absolutePath = absolutePath.replace("\\", ".");} else {path = "out/production/classes";absolutePath = absolutePath.substring(absolutePath.indexOf(path) + path.length() + 1, absolutePath.indexOf(".class"));absolutePath = absolutePath.replace("/", ".");}}return absolutePath;}/** * 列举出file下的所有class文件 */private void listPackageFiles(File file) {// 判断当前是否是目录if (file.isDirectory()) {File[] files = file.listFiles();assert files != null;if (files.length == 0) {return;}for (File f : files) {scannedFiles.add(f);// 判断当前是否是目录if (f.isDirectory()) {// 继续递归获取f下的class文件listPackageFiles(f);}}}}/** * 获取包路径下的文件 */private File getPackageFile(String basePackage) {// 这里想到我们指定的路径linc.cool,我们要转变成linc/cool,所以需要替换String path = basePackage.replace(".", "/");// 通过类加载器去获取path路径下的文件URL resource = this.getClass().getClassLoader().getResource(path);assert resource != null;return new File(resource.getFile());}/** * 获取Bean */public Object getBean(String beanName) {// 判断这个beanName在beanDefinitionMap中是否存在if (!beanDefinitionMap.containsKey(beanName)) {throw new NullPointerException(String.format("%s不存在", beanName));}// 存在就拿出beanDefinitionBeanDefinition beanDefinition = beanDefinitionMap.get(beanName);// 如果是单例就返回单例池中的对象,否则返回新的实例if ("singleton".equals(beanDefinition.getScope())) {Object singletonBean = singletonObjects.get(beanName);// 如果没有就进行创建单例Beanif (singletonBean == null) {singletonBean = createBean(beanName, beanDefinition);singletonObjects.put(beanName, singletonBean);}return singletonBean;}// 原型Bean就直接创建return createBean(beanName, beanDefinition);}/** * 创建Bean */private Object createBean(String beanName, BeanDefinition beanDefinition) {Class<?> beanClass = beanDefinition.getClazz();try {Object bean = beanClass.getConstructor().newInstance();// 如果对象有属性加了@Autowired注解的,就给它进行赋值for (Field f : beanClass.getDeclaredFields()) {if (f.isAnnotationPresent(Autowired.class)) {f.setAccessible(true);// 去单例池中找Bean,如果没有就创建f.set(bean, getBean(f.getName()));}}// Aware回调接口if (bean instanceof BeanNameAware) {((BeanNameAware) bean).setBeanName(beanName);}// 初始化前: 实现BeanPostProcessor.postProcessBeforeInitializationfor (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {bean = beanPostProcessor.postProcessBeforeInitialization(bean, beanName);}// 初始化前: 调用@PostConstruct注解的方法for (Method method : beanClass.getDeclaredMethods()) {if (method.isAnnotationPresent(PostConstruct.class)) {method.setAccessible(true);method.invoke(bean);}}// 初始化: 实现InitializingBean.afterPropertiesSetif (bean instanceof InitializingBean) {((InitializingBean) bean).afterPropertiesSet();}// 初始化后: 实现BeanPostProcessor.postProcessAfterInitializationfor (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {bean = beanPostProcessor.postProcessAfterInitialization(bean, beanName);}// 初始化后: BeanPostProcessor(Aop-->代理对象)return bean;} catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {e.printStackTrace();}return null;}/** * 注册单例beanDefinition到单例池 */private void registerBean() {for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {String beanName = entry.getKey();BeanDefinition beanDefinition = entry.getValue();// 如果是单例我们就创建bean,放到单例池if ("singleton".equals(beanDefinition.getScope())) {singletonObjects.put(beanName, createBean(beanName, beanDefinition));}}}}

进行测试

@ComponentScan(basePackages = "linc.cool")public class AppConfig {}
  • 单例测试
@Componentpublic class UserService {public void test() {System.out.println(this.getClass().getSimpleName() + ".test()...");}}
public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = (UserService) context.getBean("userService");UserService userService2 = (UserService) context.getBean("userService");System.out.println(userService);System.out.println(userService2);}}
linc.cool.service.UserService@5cad8086linc.cool.service.UserService@5cad8086
  • 原型测试
@Component@Scope("prototype")public class UserService {public void test() {System.out.println(this.getClass().getSimpleName() + ".test()...");}}
public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = (UserService) context.getBean("userService");UserService userService2 = (UserService) context.getBean("userService");System.out.println(userService);System.out.println(userService2);}
linc.cool.service.UserService@6e0be858linc.cool.service.UserService@61bbe9ba
  • 依赖注入测试
@Componentpublic class OrderService {public void test() {System.out.println(this.getClass().getSimpleName() + ".test()...");}}
@Componentpublic class UserService {@Autowiredprivate OrderService orderService;public void test() {System.out.println(this.getClass().getSimpleName() + ".test()...");orderService.test();}}
linc.cool.service.UserServicelinc.cool.service.OrderServiceUserService.test()...OrderService.test()...

实现@Value的填充功能

@Componentpublic class ValueAnnotationBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {// 遍历所有field,判断是否加了@Value,有就进行填充Stream.of(bean.getClass().getDeclaredFields()).forEach(field -> {if (field.isAnnotationPresent(Value.class)) {String value = field.getAnnotation(Value.class).value();// 如果是字符串,就进行填充if (!"".equals(value)) {try {field.setAccessible(true);field.set(bean, field.getAnnotation(Value.class).value());} catch (IllegalAccessException e) {e.printStackTrace();}}}});return bean;}}
@Componentpublic class UserService {@Autowiredprivate OrderService orderService;@Value(value = "测试数据")private String value;public void test() {System.out.println(this.getClass().getSimpleName() + ".test()...");orderService.test();System.out.println(value);}}
UserService.test()...OrderService.test()...测试数据

目前我们只是实现了填充字符串的功能,怎么实现@Value的依赖注入的功能呢?
这部分逻辑和@Autowired实现很相似

// 如果对象有属性加了@Autowired注解的,就给它进行赋值for (Field f : beanClass.getDeclaredFields()) {if (f.isAnnotationPresent(Autowired.class)) {f.setAccessible(true);// 去单例池中找Bean,如果没有就创建f.set(bean, getBean(f.getName()));} else if (f.isAnnotationPresent(Value.class)) {String value = f.getAnnotation(Value.class).value();if ("".equals(value)) {f.setAccessible(true);// 去单例池中找Bean,如果没有就创建f.set(bean, getBean(f.getName()));}}}
@Componentpublic class RoleService {public void test() {System.out.println(this.getClass().getSimpleName() + ".test()...");}}
@Componentpublic class UserService {@Autowiredprivate OrderService orderService;@Value(value = "测试数据")private String value;@Valueprivate RoleService roleService;public void test() {System.out.println(this.getClass().getSimpleName() + ".test()...");orderService.test();roleService.test();System.out.println(value);}}
public class Main {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);UserService userService = (UserService) context.getBean("userService");userService.test();}}
UserService.test()...OrderService.test()...RoleService.test()...测试数据

毕业设计范文站