Sring初始化大概流程

听完课程后自己把老师将的知识复述一遍
1.通过配置类或者xml指定扫描路径,如果在ApplicationContext的构造方法中根据扫描路径扫描当前目录极其子目录所有的class,看其是否包含@Component注解标注。
2.把bean扫描成BeanDefinition,因为后面如果要调用context的getBean()方法的话,则需判断是否单例,而看它是否单例需重新扫描class,但是Spring在new ApplicationContext()时已经扫描过class了,重新扫描的话浪费资源,故而采用BenDefinition的方式保存bean的定义,下次使用时就无需重新扫描了。
3.通过反射调用bean的构造方法新建一个bean对象(真实对象)。如果一个类有多个构造方法,则Spring需要推断出使用哪一个构造方法。
4.对象常见出来后,检查其中是否存在 @Autowired标注的属性,如果包括,则把这些属性找出来并进行依赖注入。
5.回调各种Aware

6.(初始化前)查看是否实现了 @PostContruct,若存在,则Spring会调用当前对象的方法,@PostContruct不是Spring的注解,但是Spring通过BeanPostProcessor解析该注解,使得该注解能够在Spring发挥作用
@PostConstruct注解
7.(初始化)Spring检查该对象是否实现了InitializingBean接口,如果实现了,那么Spring会调用接口方法afterPropertiesSet()
8.(初始化后)Spring检查是否需要进行AOP,如果需要进行AOP,那么Spring将生成一个代理对象(代理对象中包括一个target属性,它是真实对象的引用),如果不需要,则bean创建完毕。其中,代理对象本身并没有实现依赖注入,实现了依赖注入的是真实对象,所以在debug时,target属性对象字段才有值。
在这里插入图片描述

Spring之BeanPostProcessor(后置处理器)介绍
初始化前以及初始化后的能够实现代理模式
BeanPostProcessor
  该接口我们也叫后置处理器,作用是在Bean对象在实例化和依赖注入完毕后,在显示调用初始化方法的前后添加我们自己的逻辑。注意是Bean实例化完毕后及依赖注入完成后触发的。接口的源码如下

public interface BeanPostProcessor {
    // **初始化前回调**
    //bean:bean的实例对象,beanName:beanName:bean的名字
    //返回值:bean的实例或者是它的包装类,证明我们可以代理该bean实例
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
	//**初始化后回调**
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

}
注意:接口中两个方法不能返回null,如果返回null那么在后续初始化方法将报空指针异常或者通过getBean()方法获取不到bena实例对象
     因为后置处理器从Spring IoC容器中取出bean实例对象没有再次放回IoC容器中

在这里插入图片描述

尝试手写一个简单的ApplicationContext

package com.galss.spring;
import com.spring.BeanDefinition;
import com.spring.BeanPostProcessor;
import com.spring.InitializingBean;
import com.spring.ScopeEnum;
import com.test.service.FileUtil;
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.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class AnnotationApplicationContext implements ApplicationContext {
    //保存bean的定义信息
    Map<String ,BeanDefinition> beanDefinitionMap =new ConcurrentHashMap<>();
    List<BeanPostProcessor> beanPostProcessorList=new ArrayList<>();
    Map<String,Object> singletonBeanPool=new ConcurrentHashMap<>();
    public AnnotationApplicationContext(Class clasz) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        // 扫描类 得到 BeanDefinition
        scan(clasz);
        //实例化,属性填充,Aware回调,初始化前,初始化,初始化后
        instanceSingletonBean();

    }

    private void instanceSingletonBean() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        for (Map.Entry<String, com.spring.BeanDefinition> beanDefinitionEntry: beanDefinitionMap.entrySet()) {
             if (beanDefinitionEntry.getValue().getScope().equals(ScopeEnum.singleton)){
                Object bean= doCreateBean(beanDefinitionEntry.getKey(),beanDefinitionEntry.getValue());
                singletonBeanPool.put(beanDefinitionEntry.getKey(),bean);
             }
        }

    }
        public Object doCreateBean(String beanName,BeanDefinition beanDefinition) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
          Object bean=beanDefinition.getBeanClass().getConstructor().newInstance();
          Class beanClasz=beanDefinition.getBeanClass();
            for (Field field : beanClasz.getDeclaredFields()) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    //依赖注入
                    field.setAccessible(true);

                    field.set(bean,getBean(field.getName()));
                }
            }

            //初始化前回调
            beanPostProcessorList.forEach(beanPostProcessor -> beanPostProcessor.postProcessBeforeInitialization(beanName,bean));
            //初始化
            if (bean instanceof InitializingBean){
                ((InitializingBean)bean).afterPropertiesSet();
            }
            //初始化后回调
            beanPostProcessorList.forEach(beanPostProcessor -> beanPostProcessor.postProcessAfterInitialization(beanName,bean));
        return bean;
        }
    //通过扫描配置类指定路径中标注了@Componenet注解的类
    private void scan(Class clasz) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        ComponentScan annotation = (ComponentScan) clasz.getAnnotation(ComponentScan.class);
        String basePackge = annotation.basePackge();
        basePackge = basePackge.trim();
        String path = basePackge.replace(".", "/");
        URL resource = clasz.getClassLoader().getResource(path);
        File file=new File(resource.getFile());
        File[] listFiles = file.listFiles();
        for (File f: listFiles) {
            if (f.isFile()){
                if (f.getName().endsWith(".class")){

                    String classPath=f.getPath().replace("\\",".").substring(f.getPath().replace("\\",".").indexOf("com.test.service"),f.getPath().replace("\\",".").lastIndexOf(".class"));
                    Class<?> aClass = clasz.getClassLoader().loadClass(classPath);
                    //有两个Class类型的类象,一个是调用isAssignableFrom方法的类对象(后称对象A),以及方法中作为参数的这个类对象(称之为对象B),这两个对象如果满足以下条件则返回true,否则返回false:
                    //
                    //A对象所对应类信息是B对象所对应的类信息的父类或者是父接口,简单理解即A是B的父类或接口
                    //
                    //A对象所对应类信息与B对象所对应的类信息相同,简单理解即A和B为同一个类或同一个接口
                    //————————————————
                    //版权声明:本文为CSDN博主「艾米莉Emily」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
                    //原文链接:https://blog.csdn.net/yaomingyang/article/details/80876100
                    //BeanPostProcessor可以在初始化前以及初始化后调用,它是不针对某一个bean的定义的,而是每个bean的初始化前后都会调用BeanPostProcess,
                    //所以我们在真正初始化bean之前就应该把它new并保存起来,那么下次new 单例bean对象时就可以直接使用了
                    if (BeanPostProcessor.class.isAssignableFrom(aClass)){
                       beanPostProcessorList.add((BeanPostProcessor) aClass.getConstructor().newInstance());
                    }
                    if (aClass.isAnnotationPresent(Component.class)) {
                        Component component=aClass.getAnnotation(Component.class);
                        //是否单例
                        BeanDefinition beanDefinition=new BeanDefinition();
                        beanDefinition.setBeanClass(aClass);
                        if (aClass.isAnnotationPresent(Scope.class)) {
                            Scope scope = aClass.getAnnotation(Scope.class);
                            String value = scope.value();
                            beanDefinition.setBeanClass(aClass);
                            if (value.equals(ScopeEnum.prototype.name())){
                                beanDefinition.setScope(ScopeEnum.prototype);
                            }else {
                                beanDefinition.setScope(ScopeEnum.singleton);
                            }
                        }else {
                            beanDefinition.setScope(ScopeEnum.singleton);
                        }
                        String name=component.value().trim();
                        if (name.equals("")==false){
                            beanDefinitionMap.put(FileUtil.firstLower(name),beanDefinition);
                        }else {
                            beanDefinitionMap.put(FileUtil.firstLower(aClass.getName().substring(aClass.getName().lastIndexOf('.')+1)),beanDefinition);
                        }


                    }
                }
            }else if (f.isDirectory()){
                //扫描下一级别
            }

        }
    }

    @Override
    public Object getBean(String beanName) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        Object o = singletonBeanPool.get(beanName);
        if (o!=null){
            return o;
        }
        Object bean=doCreateBean(beanName,beanDefinitionMap.get(beanName));
        return  bean;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值