Handwrite a simple version of the Spring framework

The Spring framework is very large and complex. In order to better understand its implementation, I try to imitate its functions and write a simple version. For the time being, it only includes a few simple functions and will be updated based on the situation.

1. Contains features

  1. @ComponentScan package body scan
  2. @Autowire dependency injection
  3. @Scope singleton implementation
  4. BeanPostProcessor post processor
  5. InitializingBean initializes the bean interface
  6. BeanNameAware name resource settings
  7. BeanDefinition
  8. SingletonObjects singleton pool
  9. BeanDefinitionMap pool
  10. ApplicationContext based on annotation configuration

2. Logic

public class main {
    
    

    public static void main(String[] args) {
    
    
        EndwasApplicationContext context = new EndwasApplicationContext(AppConfig.class);
        EndwasService endwasService = (EndwasService) context.getBean("endwasService");
        endwasService.execute();
    }
}

Just like using a normal Spring container, you need to create the container and pass in the configuration class, and then get the beans.

    public EndwasApplicationContext(Class<?> configClass) {
    
    
        if (configClass == null) {
    
    
            throw new EndwasException("configClass can not null!");
        }
        this.configClass = configClass;
        init();
    }

The initialization of the container is divided into three steps:

  • Get the package body scanned by the configuration class @ComponentScan, such as com.endwas.context. If it is not set, scan the package body where the class is located.
  • Scan the current folder and subfolders for BeanDefinition creation and save metadata.
  • The singleton bean creation is saved into the singleton pool singletonObjects.
  private void init() {
    
    
        // 初始化 1、扫描 -> beanDefinitionMap 2、创建到singletonObjects
        String packageName = getPackagePath();
        // 扫描
        scan(packageName);
        // 创建bean
        createBean();
    }

To get the bean, if it is a singleton bean, you only need to get it directly from the singleton pool. If it is not a singleton bean, you can create it when you get it. Both call the createBean method when creating.

 private Object createBean(String beanName, BeanDefinition beanDefinition) {
    
    
        Class<?> clazz = beanDefinition.getClazz();
        Object bean = null;
        try {
    
    
            // 1.实例bean
            bean = clazz.getDeclaredConstructor().newInstance();

            // 2.依赖注入
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
    
    
                if (field.isAnnotationPresent(Autowired.class)) {
    
    
                    Object value = getBean(field.getName());
                    field.setAccessible(true);
                    field.set(bean, value);
                }
            }

            // 3.Aware回调
            if (bean instanceof BeanNameAware) {
    
    
                ((BeanNameAware) bean).setBeanName(beanName);
            }
            // 如果是BeanPostProcessor则不调用before/after
            if (bean instanceof BeanPostProcessor) {
    
    
                initBean(clazz, bean);
                return bean;
            }
            // 4.beanPostProcessor::postProcessBeforeInitialization
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
    
    
                bean = beanPostProcessor.postProcessBeforeInitialization(bean, beanName);
            }
            initBean(clazz, bean);

            // 6.beanPostProcessor::postProcessAfterInitialization aop动态代理
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
    
    
                bean = beanPostProcessor.postProcessAfterInitialization(bean, beanName);
            }


        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
    
    
            e.printStackTrace();
        }
        return bean;

    }

The method includes

  • Create by calling the default constructor.
  • dependency injection
  • If aware callback is implemented
  • 调用beanPostProcessor::postProcessBeforeInitialization
  • Initialize the bean (execute postConstruct, InitializingBean)
  • 调用beanPostProcessor::postProcessAfterInitialization

It should be noted here that postConstruct is executed before the post-processor is initialized, and is executed together with afterPropertiesSet.

3.Source code

It has been uploaded to github and is still being improved from time to time.
https://github.com/Endwas/EndwasApplicationContext

4.next

Follow-up plan

  1. Supports resource, inject and other annotations.
  2. PostConstruct modifies the implementation location.
  3. Supports ComponentScan multipath.

おすすめ

転載: blog.csdn.net/qq_40922616/article/details/122151211