手写模拟spring底层原理

1.对于非懒加载的单利bean,在spring容器启动时就已经创建。

// 创建一个Spring容器
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);

		UserService userService = (UserService) applicationContext.getBean("userService");
		userService.test();

项目基本结构

1.创建@ComponentScan注解,定义包扫描路劲

//定义扫描路劲
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {

    String value() default "";
}

2.创建@Component注解,向spring容器注册bean

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {

    String value() default "";
}

3.创建AppConfig配置类,定义包扫描路径。

//配置类
@ComponentScan("com.test.service")
public class AppConfig {
}

4.创建OrderService和UserService类。

@Component("userService")
@Scope("prototype")
public class UserService {

    public void test(){
        System.out.println("useService");
    }
}


public class OrderService {

    public void test(){
        System.out.println("orderService");
    }
}

5.创建TestApplicationContext容器。

public class TestApplicationContext {

    private Class configClass;

    //存储BeanDefinition对象
    private Map<String,BeanDefinition> beanDefinitionMap=new HashMap<>();

    //单例池map,存储单例bean对象
    Map<String,Object> singletonObject=new HashMap<>();

    public TestApplicationContext(Class configClass) {
        this.configClass = configClass;
    }

    public Object getBean(String name){
        return null;
    }
}

6.从容器获取bean对象。

public class Test {
    public static void main(String[] args) {
        //创建conext容器,创建单例bean,Appconfig构造方法中完成
        TestApplicationContext applicationContext = new TestApplicationContext(AppConfig.class);
        UserService userService = (UserService) applicationContext.getBean("UserService");
    }
}

至此大体框架已经完成,接下来完成如何扫描,创建bean对象,bean初始化前,初始化,初始化后的相关实现等等

  • 在TestApplicationContext 的构造方法中扫描AppConfig定义的扫描路径,扫描定义的bean。
public TestApplicationContext(Class configClass) {
       this.configClass = configClass;
       //扫描
       scan(configClass);
   }

private void scan(Class configClass) {
       //判断当前类上是否有ComponentScan注解
       if (configClass.isAnnotationPresent(ComponentScan.class)){
           ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
           String path = componentScanAnnotation.value();
           path=path.replace(".","/"); // com/test/service

           //获取target包下的class文件取出,解析注解,通过Appclassloader类加载器获取
           ClassLoader classLoader = TestApplicationContext.class.getClassLoader();
           URL resource = classLoader.getResource(path);
           File file = new File(resource.getFile());

           //取出目录下的文件,遍历
           if (file.isDirectory()){
               for (File f : file.listFiles()) {
                   String absolutePath = f.getAbsolutePath();

                   //path(C:\Users\cchuang4\IdeaProjects\springDemo\target\classes\com\test\service\OrderService.class)转换成com.test.service
                   absolutePath=absolutePath.substring(absolutePath.indexOf("com"),absolutePath.indexOf(".class"));
                   absolutePath=absolutePath.replace("\\",".");

                   try {
                       //判断class文件是否有@Component注解
                       //将class文件加载进来成为class对象
                       Class<?> clazz = classLoader.loadClass(absolutePath);
                       if (clazz.isAnnotationPresent(Component.class)){

                           //获取beanname
                           Component componentAnnotation = clazz.getAnnotation(Component.class);
                           String beanName = componentAnnotation.value();

                           //创建BeanDefinition对象
                           BeanDefinition beanDefinition = new BeanDefinition();
                           beanDefinition.setType(clazz);
                           //Bean是否为单例或原型
                           if (clazz.isAnnotationPresent(Scope.class)){
                               Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
                               String value = scopeAnnotation.value();
                               beanDefinition.setScope(value);

                           }else {
                               //单例
                               beanDefinition.setScope("singleton");
                           }
                           //将bean的相关元信息存入beandefinitionMap
                           beanDefinitionMap.put(beanName,beanDefinition);

                       }
                   } catch (ClassNotFoundException e) {
                       throw new RuntimeException(e);
                   }

               }
           }
       }
   }
  • 在TestApplicationContext容器加载的时候,如何去获取bean的一些元信息等,需要定义对一个bean元信息的描述,比如bean的class,bean的作用域,bean的Order等信息,在Spring生成bean的时候需要依赖于BeanDefinfition。

创建BeanDefinfition

package com.spring;

public class BeanDefinition {

    //类型
    private Class type;

    //作用域
    private String scope;

    //是否懒加载
    private boolean isLazy;

    public Class getType() {
        return type;
    }

    public void setType(Class type) {
        this.type = type;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }

    public boolean isLazy() {
        return isLazy;
    }

    public void setLazy(boolean lazy) {
        isLazy = lazy;
    }
}
  • 单例bean的获取去遍历beanDefinitionMap,找出所有的单例bean,并存入单例池map中,在getBean()时呢能够快速的获取单例bean。TestApplicationContext的构造方法:
public TestApplicationContext(Class configClass) {
        this.configClass = configClass;
        //扫描
        scan(configClass);

        //遍历map
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            String beanName= entry.getKey();
            BeanDefinition beanDefinition = entry.getValue();
            if (beanDefinition.getScope().equals("singleton")){
                //获取单例bean
                Object bean = createBean(beanName, beanDefinition);
                //将单例bean存进单例池的map中,在getBean()时直接拿取
                singletonObject.put(beanName,bean);
            }
        }
    }
  • 通过getBean()方法去获取bean,先通过beanDefinitionMap获取beanDefinition,再去判断是单例/原型bean,如果是单例bean,直接从单例池singletonObject中获取。
public Object getBean(String beanName){
        //判断是否有这个bean
        if (!beanDefinitionMap.containsKey(beanName)){
            throw new NullPointerException();
        }else {
            //获取beanDefinition对象
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            //判断单例/原型bean
            if (beanDefinition.getScope().equals("singleton")){
                //从单例池中直接获取
                Object singletonBean = singletonObject.get(beanName);
                return singletonBean;
            }else {
                //原型
                Object prototypeBean = createBean(beanName, beanDefinition);
                return prototypeBean;
            }
        }
    }

createBean()方法,创建bean对象

Object createBean(String beanName,BeanDefinition beanDefinition){
        Class clazz = beanDefinition.getType();
        Object instance = null;
        try {
            instance = clazz.getConstructor().newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        return instance;
    }

至此已经支持单例bean和原型bean的获取。

!!!测试运行Test类

1.当userService的@Scope("singleton")时:

1.当userService的@Scope("prototype")时:

此时@Component注解上要指定beanName,否则会NPE,如何获取默认的bean的名字?

//设置默认beanName
   if (beanName.equals("")){
       beanName= Introspector.decapitalize(clazz.getSimpleName());
   }

@AutoWire依赖注入的实现

  • 创建Autowired注解,并在Userservice里添加OrderService属性。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {

    String value() default "";
}

UserService.class

@Component("userService")
@Scope("prototype")
public class UserService {

    @Autowired
    private OrderService orderService;

    public void test(){
        System.out.println(orderService);
    }
}
  • 在创建bean时进行依赖注入,先根据type,再根据name去容器中找。createBean():
Object createBean(String beanName,BeanDefinition beanDefinition){
        Class clazz = beanDefinition.getType();
        Object instance = null;
        try {
            instance = clazz.getConstructor().newInstance();
            //依赖注入
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(Autowired.class)){
                    field.setAccessible(true);
                    //根据type去单例池或beanDefinitionMap中去找
                    //...省略
                    //根据beanName去找
                    field.set(instance,getBean(beanName));
                }
            }
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        return instance;
    }
  • 此时若先扫描到UserService,然后去创建UserService这个bean,然后在上面依赖注入的field.set(instance,getBean(beanName))时,此时OrderService单例池中还没有创建这个bean,依赖注入就会出问题。此时在创建bean时再去判断bean是否存在,不存在则再生成。
    public Object getBean(String beanName){
        //判断是否有这个bean
        if (!beanDefinitionMap.containsKey(beanName)){
            throw new NullPointerException();
        }else {
            //获取beanDefinition对象
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            //判断单例/原型bean
            if (beanDefinition.getScope().equals("singleton")){
                //从单例池中直接获取
                Object singletonBean = singletonObject.get(beanName);
                //若此时对应的bean还没有创建,如在依赖注入时
                if (singletonBean==null){
                    singletonBean=createBean(beanName,beanDefinition);
                    singletonObject.put(beanName,singletonBean);
                }
                return singletonBean;
            }else {
                //原型
                Object prototypeBean = createBean(beanName, beanDefinition);
                return prototypeBean;
            }
        }
    }

测试,输出UserService里的OrderService对象:

此时依赖注入已经完成

初始化(InitializingBean接口)

  • 创建InitializingBean接口
public interface InitializingBean{

    void afterPropertiesSet() throws Exception;
}

UserService.class

@Component("userService")
@Scope("prototype")
public class UserService implements InitializingBean {

    @Autowired
    private OrderService orderService;

    public void test(){
        System.out.println(orderService);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("afterPropertiesSet");
    }
}

此时在UserService加载时afterPropertiesSet不能自动调到。

  • 在createBean()之后判断当前实例是否实现了InitializingBean 接口,实现了则调用afterPropertiesSet方法。
//调用实现了InitializingBean的afterPropertiesSet方法
if (instance instanceof InitializingBean){
                ((InitializingBean)instance).afterPropertiesSet();
            }

BeanPostProcessor的实现

  • 该接口也叫后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。

  • 创建BeanPostProcessor接口

public interface BeanPostProcessor {

    default Object postProcessBeforeInitialization(Object bean, String beanName){
        return bean;
    }

    default Object postProcessAfterInitialization(Object bean, String beanName){
        return bean;
    }
}
  • 创建自己的类,去实现BeanPostProcessor接口,在类上加上@Component(自定义注解),以便被spring托管扫描到。在包扫描(scan()方法)时,会判断如果当前类上有@Component注解,然后会判断是否实现了BeanPostProcessor注解,

此时的bean的后置处理器会针对所有bean,若想针对其中一个bean,则需自己写处理逻辑。

@Component
public class TestBeanPostProcessor  implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println(beanName);
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
}
  • 创建在扫描时扫描到的那些实现了BeanPostProcessor接口的对象的list集合。
    //存放BeanPostProcessor对象
    List<BeanPostProcessor> beanPostProcessorList=new ArrayList<>();
  • 在scan时判断扫描到的那些bean是否实现了BeanPostProcessor接口,实现了则加入list集合中。
if (clazz.isAnnotationPresent(Component.class)){
                            //判断类是否实现了BeanPostProcessor接口
                            if (BeanPostProcessor.class.isAssignableFrom(clazz)){
                                //获得BeanPostProcessor的实例
                                BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();
                                //将BeanPostProcessor对象存入list(LinkList)
                                beanPostProcessorList.add(instance);
                            }
                    ......
  • 在createBean()时,在调用了实现InitializingBean的afterPropertiesSet()方法之后,再去调用BeanPostProcessor接口的方法。
            //调用初始化后方法
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
            }

       此时BeanPostProcessor 的postProcessAfterInitialization方法返回值再次赋值给instance对象,基于这一原理可以实现AOP功能,在postProcessAfterInitialization方法里去实现一些切面的逻辑,以及可以在bean初始化前,初始化后去做一些其他的事情,如自定义注解给字段设置默认值等等。

posted @ 2022-11-06 22:55  StudyHardWork  阅读(101)  评论(0编辑  收藏  举报