手撕spring框架(1)

相关系列

java中spring底层核心原理解析(1)-CSDN博客

java中spring底层核心原理解析(2)-CSDN博客

手撕spring框架(2)-CSDN博客

手撕spring框架(3)-CSDN博客

手撕spring框架(4)-CSDN博客

在以上详细讲解了spring底层核心原理,今天我们就来手写一个spring框架。主流程是:

1、编写启动类

2、依据ComponentScan设置的value属性进行扫描路径下的文件

3、根据扫描得到的文件,判断是否加了Component注解,如果加了,则添加到beanDefinitionMap

4、编写DzendApplicationContext中的getBean方法,判断是单例bean还是原型bean,单例bean则到singletonObjects中去获取,如果为null,则创建;如果是原型bean,则创建;把刚获取的bean返回,就拿到了bean

 第一步编写启动类Test.java

这个类是应用程序的主入口,用于程序的启动

package com.dzend;

import com.dzend.service.UserService;
import com.spring.DzendApplicationContext;

public class Test {

    public static void main(String[] args) {
        //扫描   ->创建对象
        DzendApplicationContext applicationContext = new DzendApplicationContext(AppConfig.class);

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

    }
}

第二步编写配置类AppConfig.java

是一个配置类,用以配置要扫描的文件路径。 

package com.dzend;


import com.spring.ComponentScan;

@ComponentScan("com.dzend.service")
public class AppConfig {
}

第三步,根据第二步用了@ComponentScan注解,创建ComponentScan注解

用来配置扫描路径的注解。

package com.spring;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

    String value() default "";
}

Component.java

用于配置要加入到BeanDefinitionMap 中,也就是管理这个service类的,比如缓存。

package com.spring;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

 Scope.java

用于标注是单例bean,还是原型bean。在创建bean的时候,如果是单例bean,则从singletonObjects对象获取,如果值为null,则创建这个对象,并放入到 singletonObjects对象中。如果为原型bean,则每次获取的时候都动态的创建新类并返回。

package com.spring;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

第四步编写DzendApplicationContext.java文件

这是一个核心文件,用来工作的,核心就是扫描路径,创建 singletonObjects。

package com.spring;

import java.beans.Introspector;
import java.io.File;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class DzendApplicationContext {

    private Class<?> configClass;

    private Map<String,BeanDefinition> beanDefinitionMap= new HashMap<>();

    private Map<String, Object> singletonObjects=new HashMap<>();

    private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

    public DzendApplicationContext(Class configClass)   {
        this.configClass=configClass;

        scan(configClass);

    }

    private void scan(Class configClass) {
        if(configClass.isAnnotationPresent(ComponentScan.class)){
            ComponentScan componentScan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            String path = componentScan.value();
            path = path.replace(".","/");


            ClassLoader classLoader = DzendApplicationContext.class.getClassLoader();
            URL resource = classLoader.getResource(path);

            try {
                path = URLDecoder.decode(path, "UTF-8");
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }
            File file = null;
            try {
                file = new File(  URLDecoder.decode(resource.getFile(), "UTF-8"));
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException(e);
            }



            if(file.isDirectory()){

                for (File f : file.listFiles()) {
                    String absolutePath = f.getAbsolutePath();

                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"),absolutePath.indexOf(".class"));
                    absolutePath=absolutePath.replace("\\",".");


                    try {
                        Class<?>  clazz = classLoader.loadClass(absolutePath);

                        if (clazz.isAnnotationPresent(Component.class)) {

                            if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
                                BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();
                                beanPostProcessorList.add(instance);
                            }


                            Component componentAnnotaion = clazz.getAnnotation(Component.class);
                            String beanName= componentAnnotaion.value();
                            if("".equals(beanName)){
                                beanName = Introspector.decapitalize(clazz.getSimpleName());
                            }

                           BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setType(clazz);

                            if (clazz.isAnnotationPresent(Scope.class)) {
                                Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
                                String value = scopeAnnotation.value();
                                beanDefinition.setScope(value);
                            }else{
                                beanDefinition.setScope("singleton");
                            }

                            beanDefinitionMap.put(beanName,beanDefinition);

                        }

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


                }
            }

        }
    }

    public Object getBean(String beanName){
        if(!beanDefinitionMap.containsKey(beanName)){
            throw new NullPointerException();
        }

        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(beanDefinition.getScope().equals("singleton")){
            Object singletonObject = singletonObjects.get(beanName);

            if(singletonObject == null){
                singletonObject = createBean(beanName,beanDefinition);
                singletonObjects.put(beanName,singletonObject);
            }
            return singletonObject;
        }else{
            //原型
            Object prototypeBean = createBean(beanName, beanDefinition);
            return prototypeBean;
        }

    }

    private 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;
    }
}

编写相关service类

定义相关的业务类,并加上Component注解用来标注是不是要放入spring容器中缓存。 

OrderService.java

package com.dzend.service;


import com.spring.Autowired;
import com.spring.Component;

@Component(value = "orderService")
public class OrderService {


    public void test(){
        System.out.println("Hello world!!!");
    }

}

UserService.java

package com.dzend.service;


import com.spring.Autowired;
import com.spring.BeanNameAware;
import com.spring.Component;

@Component(value = "userService")
public class UserService  {

   
    @Autowired
    private OrderService orderService;

  


 
    public OrderService getOrderService() {
        return orderService;
    }

 
}

  • 33
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值