Spring源码系列-手写spring的核心逻辑

1.了解Spring工作的大概流程

2.属性BeanDefinition,BeanFactory,Bean等基本概念

3.熟悉Bean的生命周期,Bean的后置处理器等基本概念

1.首先我们可以先自定义几个注解@Componet

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Componet {
    String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Lazy {

}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
    String value() default "";
}

2.我们定义一个自己的启动类

/**
 * 1.自定义注解:Componet
 * 2.创建LubanApplicationContext
 *   LubanApplicaitonContext的作用就是启动spring,帮助我们去创建bean,这样我们才能在下面进行getBean
 *   启动的时候就直接创建吗?启动spring,难道所有的类都要创建bean,当然不是,首先我们要确定发扫描路径,所以我们要进行扫描
 *
 *   步骤:启动  扫描(确定包路径) 只有加了@conponet注解的才创建  创建bean(非懒加载的单例Bean)
 */
public class Application {
    public static void main(String[] args) {
        LubanApplicaitonContext context=new LubanApplicaitonContext(Appconfig.class);
        TestService testService = (TestService) context.getBean("testService");
        testService.test();
        //接下来实现自动注入的功能:什么时候来自动注入的呢?在createBean的时候,我们创建完一个Bean,需要属性及逆行填充

    }
}

那么我们怎么来确定扫描的路径呢?当然自己手写一个Appconfig,并加上我们的@ComponetScan

import com.luban.framework.ComponetScan;

@ComponetScan("com.luban.service")
public class Appconfig {
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponetScan {
    String value() default "";
}

那么我们就开始沿着我们的步骤来:启动 扫描(确定包路径) 只有加了@conponet注解的才创建 创建bean(非懒加载的单例Bean)

环节2:扫描

ublic class LubanApplicaitonContext {
    private Class appconfigClass;
    private Map<String,BeanDefinition> beanDefinitionMap=new HashMap<>();//beandefinitionmap
    private Map<String,Object> singletonObjects=new HashMap<>();//单例池
    private List<BeanPostProcessor> BeanPostProcessors=new ArrayList<>();//后置处理器
    public LubanApplicaitonContext(Class appconfigClass) {
        this.appconfigClass = appconfigClass;
        //扫描
        scan(appconfigClass);
        //创建非懒加载的单例Bean
        createNonLazySingleton();

    }
//首先来看扫描scan(appconfigClass);
public void scan(Class appconfigClass){//获得我们的Appconfig
      if (appconfigClass.isAnnotationPresent(ComponetScan.class)) {//看我们的Appconfig有没有ComponetScan这个注解
            ComponetScan componetScanAnnotation = (ComponetScan) appconfigClass.getAnnotation(ComponetScan.class);//获得注解
            String path = componetScanAnnotation.value();//获得注解的名字,也即是我们的扫描路径
            //其实扫描路径是classes下面的class文件并不是.java文件,所以获得的com.luban.service就只是我们的包名
           //-classpath: E:\JAVA\JavaSE\Test2\target\classes 这个就是我们的路径名
            System.out.println(path);//com.luban.service

            path= path.replace(".","/");
            //因为我们的类路径是由AppClassLoader加载的,所以我们可以使用类加载器
            ClassLoader classLoader=LubanApplicaitonContext.class.getClassLoader();
            URL resource = classLoader.getResource(path);//获取一个资源,里面我们可以传一个相对路径,相对于我们的-calsspath: E:\JAVA\JavaSE\Test2\target\classes正符合要求
            File file=new File(resource.getFile());//此时我们得到的就是一个文件夹 service
            for (File f : file.listFiles()) {//E:\JAVA\JavaSE\Test2\target\classes\com\luban\service\OrderService.class
                //此时我们就得到了Class文件,转成Class对象下面我们的思路就是判断是否存在@componet注解,其实在spring中就是使用ASM技术直接去判断字节码
                //如何得到呢Class对象呢?还是使用classLoader
                String s = f.getAbsolutePath();
                if (s.endsWith(".class")) {
                    s=s.substring(s.indexOf("com"),s.indexOf(".class"));
                    s=s.replace("\\",".");//s :com.luban.service.Testservice
                    try {
                        Class clazz = classLoader.loadClass(s);//获取需要加载类的Class对象
                        System.out.println(clazz);
                        //我们确定了扫描的路径,下面就是确定那个类可以成为一个bean了
                        if (clazz.isAnnotationPresent(Componet.class)) {//是否存在这个@Componet注解
                            //BeanPostProcessor先不用看,我一会会说
                           /*if(BeanPostProcessor.class.isAssignableFrom(clazz)){//判断这个类是一个BeanPostProcessor
                                BeanPostProcessor declaredConstructor = (BeanPostProcessor) clazz.getDeclaredConstructor().newInstance();
                                BeanPostProcessors.add(declaredConstructor);
                            }*/
                            //有componet就证明这是一个Bean,但是创建的话,需要判断是不是非懒加载的单例Beanc
                            //获取Component注解的信息,其实就是componet的beanName
                            //Beandefinition把我对bean的解析存放起来,这样在getBean的时候就可以直接拿
                            BeanDefinition beanDefinition=new BeanDefinition();
                            beanDefinition.setBeanClass(clazz);
                            Componet Componetannotation = (Componet) clazz.getAnnotation(Componet.class);
                            String beanName = Componetannotation.value();//componet配置的beanName
                            if (clazz.isAnnotationPresent(Lazy.class)) {//是不是懒加载的
                                beanDefinition.setLazy(true);
                            }
                            if(clazz.isAnnotationPresent(Scope.class)){
                                Scope Scopeannotation = (Scope) clazz.getAnnotation(Scope.class);
                                String value = Scopeannotation.value();//获取Scope的值
                                beanDefinition.setScope(value);
                            }else {
                                beanDefinition.setScope("singleton");
                            }
                            beanDefinitionMap.put(beanName,beanDefinition);
                        }

                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }

        }

现在我们先看一下getBean,引进来beandefinition

/**
 * bean对象和Beandefinition,现有Beandefinition
 */
public class BeanDefinition {
    private String Scope;
    private boolean isLazy;
    private Class beanClass;

    public String getScope() {
        return Scope;
    }

    public void setScope(String scope) {
        Scope = scope;
    }

    public boolean isLazy() {
        return isLazy;
    }

    public void setLazy(boolean lazy) {
        isLazy = lazy;
    }

    public Class getBeanClass() {
        return beanClass;
    }

    public void setBeanClass(Class beanClass) {
        this.beanClass = beanClass;
    }
}
public Object getBean(String beanName) {
    //如果我能确定这个beanName对应的就是这个类,那么我还要看一下这个类是单例的还是原型的
     //所以说,我还要在getBean里面去解析这个类,
    //是单例,单例池中拿,原型,在创建一个,spring是只判断一次的,这就牵扯到了Beandefinition
    //也就是把bean的解析存储起来  scope lazy
    if (!beanDefinitionMap.containsKey(beanName)) {
        throw new NullPointerException();
    }else {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(beanDefinition.getScope().equals("singleton")){
            //从单例池中获取
            Object o = singletonObjects.get(beanName);
            if(o==null){//如果单例池中不存在,就创建一个,放进去
                Object bean = createBean(beanDefinition,beanName);
                singletonObjects.put(beanName,bean);
            }
            return o;
        }else if(beanDefinition.getScope().equals("prototype")){
            //重新创建一个 并返回
            Object bean = createBean(beanDefinition,beanName);
            return bean;
        }
    }
    return null;
}

环节3:创建非懒加载的单例Bean

private void createNonLazySingleton() {
    for (String beanName : beanDefinitionMap.keySet()) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(beanDefinition.getScope().equals("singleton")&& !beanDefinition.isLazy()){
            Object bean = createBean(beanDefinition,beanName);//如果是单例,那么我们就需要吧我们的bean放到到单例池当中
            singletonObjects.put(beanName,bean);
        }
    }
}
private  Object createBean(BeanDefinition beanDefinition,String beanName){
    //怎样去创建一个Bean呢?
    Class beanClass = beanDefinition.getBeanClass();
    try {
        Object instance = beanClass.getDeclaredConstructor().newInstance();//这个时候Bean已经创建好了,下面就是一些扩展

        //最后知识点 Bean的后置处理器
        //如果我们在每个属性上加上了@Autowired和@resources,那么我们需要分开来处理
        //同时@Autowired使用的是AutowiredAnnotationBeanPostProcessor,@Reources使用的是CommAnnotationBeanPostProcessor
        //spring还给我们提供了自定义,

        for (BeanPostProcessor beanPostProcessor : BeanPostProcessors) {
            beanPostProcessor.Autowired();
        }
        //填充属性 1、遍历字段,也就是你的加了@Autowired注解的才填充
        /*for (Field field : beanClass.getDeclaredFields()) {
            if (field.isAnnotationPresent(Autowired.class)) {
                //我要给这个属性赋什么值呢?这个值又从哪里来呢?
                //这里就涉及了ByName,ByType  单例模式和单例Bean是不一样的,单例模式:整个JVM中只有一个对象,但是单例Bean呢 两个@Bean也完全没有问题
                //所以Autowired是先按照类型来找,有可能拿到多个,这种情况下就可以是哟个ByName来唯一的获取一个
                //为什么不直接按照ByName呢?因为名字虽然对上,但类型对不上,会更加的没用,@Resource就是先使用的ByName,这个和JNDI很相似,因为name---资源
                String name = field.getName();
                Object bean = getBean(name);
                field.setAccessible(true);//开启
                field.set(instance,bean);
            }
        }*/
        if(instance instanceof BeanNameAware){
            ((BeanNameAware) instance).setName(beanName);
        }
        if(instance instanceof InitializingBean){
            ((InitializingBean) instance).afterpropertiesSet();//执行的时机
        }
        return instance;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

延申段~~~

@Autowired

@Componet("testService")
@Scope("prototype")
public class TestService  {//当一个bean想知道自己的名字的时候,可以实现这个接口
    @Autowired                                                       //做一些初始化的逻辑
    private OrderService orderService;
    private String beanName;

    public OrderService getOrderService() {
        return orderService;
    }

    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }


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

@Autowired的时机就是创建好了Bean,然后对属性进行填充,这可能牵扯到先后加载的问题,我们在getName的时候做了判断,如果属性填充的bean不存在,就其创建一个,加入单例池

private  Object createBean(BeanDefinition beanDefinition,String beanName){
    //怎样去创建一个Bean呢?
    Class beanClass = beanDefinition.getBeanClass();
    try {
        Object instance = beanClass.getDeclaredConstructor().newInstance();

        //填充属性 1、遍历字段,也就是你的加了@Autowired注解的才填充
        for (Field field : beanClass.getDeclaredFields()) {
            if (field.isAnnotationPresent(Autowired.class)) {
                //我要给这个属性赋什么值呢?这个值又从哪里来呢?
                //这里就涉及了ByName,ByType  我只写了ByName的方式单例模式和单例Bean是不一样的,单例模式:整个JVM中只有一个对象,但是单例Bean呢 两个@Bean也完全没有问题,只要是BeanName不一样就OK
                //所以Autowired是先按照类型来找,有可能拿到多个,这种情况下再使用ByName来唯一的获取一个
                //为什么不直接按照ByName呢?因为名字虽然对上,但类型对不上,会更加的没用,@Resource就是先使用的ByName,这个和JNDI很相似,因为name---资源
                String name = field.getName();//我们是简单的按照属性名来进行 
                Object bean = getBean(name);
                field.setAccessible(true);//开启
                field.set(instance,bean);//给那个对象,填充什么值
            }
        }
        if(instance instanceof BeanNameAware){
            ((BeanNameAware) instance).setName(beanName);
        }
        if(instance instanceof InitializingBean){
            ((InitializingBean) instance).afterpropertiesSet();//执行的时机
        }
        return instance;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

BeanNameAware和InitializingBean

ublic class TestService implements BeanNameAware, InitializingBean {//当一个bean想知道自己的名字的时候,可以实现这个接口
    @Autowired                                                       //InitializingBean做一些初始化的逻辑
    private OrderService orderService;
    private String beanName;//我想使用beanName来存储这个类的beanName;我们可以写一个这样的接口

    public OrderService getOrderService() {
        return orderService;
    }

    public void setOrderService(OrderService orderService) {
        this.orderService = orderService;
    }


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

    @Override
    public void setName(String name) {//重写这个方法
    this.beanName=name;
    }

    @Override
    public void afterpropertiesSet() {//可以对我们bean里面的一些属性进行验证
     if(orderService==null){
         //抛异常
     }
    }
}
package com.luban.framework;

public interface BeanNameAware {
    public void setName(String name);

}

public interface InitializingBean {
    public void afterpropertiesSet();
}

逻辑判断在哪儿?、

private  Object createBean(BeanDefinition beanDefinition,String beanName){
    //怎样去创建一个Bean呢?
    Class beanClass = beanDefinition.getBeanClass();
    try {
        Object instance = beanClass.getDeclaredConstructor().newInstance();
        //填充属性 1、遍历字段,也就是你的加了@Autowired注解的才填充
        for (Field field : beanClass.getDeclaredFields()) {
            if (field.isAnnotationPresent(Autowired.class)) {
                //我要给这个属性赋什么值呢?这个值又从哪里来呢?
                //这里就涉及了ByName,ByType  单例模式和单例Bean是不一样的,单例模式:整个JVM中只有一个对象,但是单例Bean呢 两个@Bean也完全没有问题
                //所以Autowired是先按照类型来找,有可能拿到多个,这种情况下就可以是哟个ByName来唯一的获取一个
                //为什么不直接按照ByName呢?因为名字虽然对上,但类型对不上,会更加的没用,@Resource就是先使用的ByName,这个和JNDI很相似,因为name---资源
                String name = field.getName();
                Object bean = getBean(name);
                field.setAccessible(true);//开启
                field.set(instance,bean);
            }
        }
        if(instance instanceof BeanNameAware){//填充完属性在进行设置
            ((BeanNameAware) instance).setName(beanName);
        }
        if(instance instanceof InitializingBean){
            ((InitializingBean) instance).afterpropertiesSet();//执行的时机
        }
        return instance;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

BeanPostProcessor

public class TestService implements BeanNameAware, InitializingBean {//当一个bean想知道自己的名字的时候,可以实现这个接口
    @Autowired                                                       //做一些初始化的逻辑
    private OrderService orderService;
    @Resources
    private UserService userService;
    private String beanName;
    
    //存在这样的情况,一个类中使用的是@Autowired,另一个使用的是@Reources,如果解析的话,会分开解析,因为它们两个使用的后置处理器也不一样,Autowired使用的是AutowiredAnnotationBeanPostProcessor,而@Resources使用的就是CommonAnnotationBeanPostProcessor,而且我们还可以自定义注解,自己写BeanPostProcessor
public interface BeanPostProcessor {
    public void Autowired();
}
@Componet
public class AutowiredAnnotationBeanPostProcessor implements BeanPostProcessor {
    @Override
    public void Autowired() {
        System.out.println("Autowired注解");
    }
}
@Componet
public class CommonAnnotationBeanPostProcessor implements BeanPostProcessor {
    @Override
    public void Autowired() {
        System.out.println("Resource注解");
    }
}
@Componet
public class LubanAnnotationBeanPostProcessor implements BeanPostProcessor {
    @Override
    public void Autowired() {
        System.out.println("LubanAutowiredBeanPostProccessor注解");
    }
}

这三个都是组件,把他们加入到spring容器中。

判断逻辑在scan中也存在

if (clazz.isAnnotationPresent(Componet.class)) {
    if(BeanPostProcessor.class.isAssignableFrom(clazz)){//判断这个类是一个BeanPostProcessor
        BeanPostProcessor declaredConstructor = (BeanPostProcessor) clazz.getDeclaredConstructor().newInstance();
        BeanPostProcessors.add(declaredConstructor);
    }
    //有componet就证明这是一个Bean,但是创建的话,需要判断是不是非懒加载的单例Beanc
    //获取Component注解的信息
    BeanDefinition beanDefinition=new BeanDefinition();
    beanDefinition.setBeanClass(clazz);
    Componet Componetannotation = (Componet) clazz.getAnnotation(Componet.class);
    String beanName = Componetannotation.value();//componey配置的beanName
    if (clazz.isAnnotationPresent(Lazy.class)) {
        beanDefinition.setLazy(true);
    }
    if(clazz.isAnnotationPresent(Scope.class)){
        Scope Scopeannotation = (Scope) clazz.getAnnotation(Scope.class);
        String value = Scopeannotation.value();//获取Scope的值
        beanDefinition.setScope(value);
    }else {
        beanDefinition.setScope("singleton");
    }
    beanDefinitionMap.put(beanName,beanDefinition);
}
private  Object createBean(BeanDefinition beanDefinition,String beanName){
    //怎样去创建一个Bean呢?
    Class beanClass = beanDefinition.getBeanClass();
    try {
        Object instance = beanClass.getDeclaredConstructor().newInstance();

        //最后知识点 Bean的后置处理器
        //如果我们在每个属性上加上了@Autowired和@resources,那么我们需要分开来处理
        //同时@Autowired使用的是AutowiredAnnotationBeanPostProcessor,@Reources使用的是CommAnnotationBeanPostProcessor
        //spring还给我们提供了自定义,

        for (BeanPostProcessor beanPostProcessor : BeanPostProcessors) {
            beanPostProcessor.Autowired();//这个里面就是我们去判断注解是@Resources还是@Autowired的逻辑了
        }
        if(instance instanceof BeanNameAware){
            ((BeanNameAware) instance).setName(beanName);
        }
        if(instance instanceof InitializingBean){
            ((InitializingBean) instance).afterpropertiesSet();//执行的时机
        }
        return instance;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}
因为:public class TestService implements BeanNameAware, InitializingBean {//当一个bean想知道自己的名字的时候,可以实现这个接口
    @Autowired                                                       //做一些初始化的逻辑
    private OrderService orderService;
    @Resources
    private UserService userService;
    
    //有两个这样的注解,所以执行了两次,其实应该在那三个BeanpostProcessor中去判断的,就可以实现不同的BeanPostProcessor去解析@Autowired和@Resources了

在这里插入图片描述
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值