当前位置: 首页>编程语言>正文

spring生成不重复数字ID 重写spring

目录

1.自动扫描bean注入

 2.getBean

3.实现依赖注入

4.实现AOP功能


码云地址:   https://gitee.com/xzc_1033426945/alibabacloud.git

通过仿写spring一方面可以更好体会领悟其设计思想,理解设计模式,另一方面可以更好的理解spring本身的底层原理  先实现主干功能,再完善细节扩展点的顺序编写 持续更新

扩大1.自动扫描bean注入

经典入口重写实现

/**
 * @author xzc
 */
public class Test {

    public static void main(String[] args) {

        XzcApplicationContext applicationContext = new XzcApplicationContext(XzcAppConfig.class);
        UserInterface userService = (UserInterface) applicationContext.getBean("userService");
        userService.test();

    }
}

1.自定义标签的写法 new选择标签

spring生成不重复数字ID 重写spring,spring生成不重复数字ID 重写spring_java,第1张

自定义sacn标签 

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

 配置标签

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

}

显然我们需要重写的内容围绕写一个自己的context  和自己config配置类

初步重写context构造方法

private Class configClass;
    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
    private Map<String, Object> singletonObjects = new HashMap<>();
    private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();


    /**
     * 首先梳理主流程
     * 1.构造方法创建context 入参为配置类
     * 2.解析配置类信息做bean扫描
     * 3.创建单例Bean
     * 4.BeanDefinition
     * 5.BeanPostPRocess
     */
    public XzcApplicationContext(Class configClass) {
        this.configClass = configClass;

        // 解析配置类信息做bean扫描
        scan(configClass);
    }

写扫描bean的scan方法 先判断标签是否齐全 有config 和 scan标签

/**
     * 解析配置类信息做bean扫描
     * 1.扫描判断传入类是否有有我们自定义注解@ComponentXzcScan的类 有进入 没有跳过
     *
     * @param configClass
     */
    private void scan(Class configClass) {
        System.out.println("scan  configClass" + configClass);
        if (configClass.isAnnotationPresent(ConfigurationXzc.class)) {
            if (configClass.isAnnotationPresent(ComponentXzcScan.class)) {
                ComponentXzcScan componentScanAnnotation = (ComponentXzcScan) configClass.getAnnotation(ComponentXzcScan.class);
                scanComponentXzcScan(componentScanAnnotation);
            }
        }
    }

标签齐全 执行扫描方法 递归扫描class文件  解析出获得beanDefinition存入 beanDefinitionMap

这之前需要 先自定义一个极简单的beanDefinition

/**
 * @Author: xzc
 * @Date: 2021/9/4 21:11
 * @Version 1.0
 */
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;
    }
}

 配套标签@ScopeXzc

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

其实实现scanComponentXzcScan 

/**
     * 1.拿传入ComponentXzcScan类的 包扫描路径
     * 2.拿appClassLoader的类加载器
     * 3.类加载器按照包扫描路径 去扫描字节码文件
     *
     * 3.1 找有@ComponentXzc标签的类 解析出beanDefinition 放入beanDefinitionMap
     *
     * @param componentScanAnnotation
     */
    private void scanComponentXzcScan(ComponentXzcScan componentScanAnnotation) {
        String path = componentScanAnnotation.value();
        path = path.replace(".", "/");
        ClassLoader appClassLoader = XzcApplicationContext.class.getClassLoader();
        URL resource = appClassLoader.getResource(path);
        String f1 = resource.getFile();
        File file = new File(f1);
        /**3.1 类加载器按照包扫描路径 去扫描加载字节码文件 */
        if (file.isDirectory()) {
            for (File f : file.listFiles()) {
                try {
                    String absolutePath = f.getAbsolutePath();
                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
                    absolutePath = absolutePath.replace("\", ".");
                    Class<?> clazz = appClassLoader.loadClass(absolutePath);

                    /**
                     * 3.2 如果加载到ComponentXzc标签的类
                     */
                    if (clazz.isAnnotationPresent(ComponentXzc.class)) {


                        /**
                         * 3.21 clazz解析出填充该bean的beanDefinition属性 并放入beanDefinitionMap中
                         */
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setType(clazz);

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

                        ComponentXzc componentAnnotation = clazz.getAnnotation(ComponentXzc.class);
                        String beanName = componentAnnotation.value();
                        if ("".equals(beanName)) {
                            beanName = Introspector.decapitalize(clazz.getSimpleName());
                        }
                        beanDefinitionMap.put(beanName, beanDefinition);

                        /**
                         * 3.22 clazz调用构造方法创建实例放入 后置处理器beanPostProcessorList中
                         */
                        if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
                            BeanPostProcessor instance = (BeanPostProcessor) clazz.getConstructor().newInstance();
                            beanPostProcessorList.add(instance);
                        }
                    }

                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

有了 beanDefinitionMap  回到原来的构造方法 我们可以在写ioc容器了

/**
     * 首先梳理主流程
     * 1.构造方法创建context 入参为配置类
     * 2.解析配置类信息做bean扫描
     * 3.BeanDefinition
     * 4.创建单例Bean的单例池 singletonObjects
     * 5.BeanPostPRocess
     */
    public XzcApplicationContext(Class configClass) {
        this.configClass = configClass;

        // 解析配置类信息做bean扫描
        scan(configClass);

        /**
         * beanDefinitionMap 我们就可以写单例池了
         */
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = entry.getValue();
            if (beanDefinition.getScope().equals("singleton")) {
                Object bean = createBean(beanName, beanDefinition);
                singletonObjects.put(beanName, bean);
            }
        }
    }

有了beanname beanDefinition 来创建creatBean

/**
     * 根据beanDefinition创建bean
     * @param beanName
     * @param beanDefinition
     * @return
     */
    private Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getType();
        Object instance = null;
        try {
            instance = clazz.getConstructor().newInstance();
       
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } 
        return instance;
    }

 2.getBean

/**
     * 获取bean
     * 1.先去beanDefinitionMap里面拿有没有beanName对应的BeanDefinition
     * 2,如果有取出来判断是否为单例
     * 3.返回 bean
     *
     * @param beanName
     * @return
     */
    public Object getBean(String beanName) {
        if (beanDefinitionMap.containsKey(beanName)) {
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            /**
             * 2.1如果为单例  去单例池拿 如果没有 就调creatbean创建一份 放入 再返回
             */
            if (beanDefinition.getScope().equals("singleton")) {
                Object singletonBean = singletonObjects.get(beanName);
                if (singletonBean == null) {
                    singletonBean = createBean(beanName, beanDefinition);
                    singletonObjects.put(beanName, singletonBean);
                }
                return singletonBean;
            }
            /**
             * 2.2如果为原型 直接调createBean创建一份
             */
            else if (beanDefinition.getScope().equals("prototype")) {
                // 原型
                Object prototypeBean = createBean(beanName, beanDefinition);
                return prototypeBean;
            } else {
                System.out.println("只考虑单例多例 其他 未完待续");
            }
        } else {
            System.out.println("这个Bean 未定义");
        }
        return null;
    }

 试一把

@ComponentXzc
@ScopeXzc(value = "singleton")
public class UserService implements UserInterface{
    @Override
    public void test() {
        System.out.println("UserService test");
    }
}

spring生成不重复数字ID 重写spring,spring生成不重复数字ID 重写spring_spring_02,第2张

一个最基本可用的spring context就实现了

3.实现依赖注入

先定义标签@AutowiredXzc   这里的ElementType.FIELD

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

重写我们的getBean方法 添循环扫描字段标签@AutowiredXzc的 扫到调getBean注入

(递归 spring循环依赖问题就在这里了)

/**
     * 根据beanDefinition创建bean
     * @param beanName
     * @param beanDefinition
     * @return
     */
    private Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz = beanDefinition.getType();
        Object instance = null;
        try {
            instance = clazz.getConstructor().newInstance();
            /**
             * 1.for循环遍历字段找到字段里的@AutowiredXzc标签
             * 2.调用getBean方法去拿bean注入
             *     这里是一个递归 就是spring经典的循环依赖问题了
             */
            for (Field field : clazz.getDeclaredFields()) {
                if (field.isAnnotationPresent(AutowiredXzc.class)) {
                    field.setAccessible(true);
                    field.set(instance, getBean(field.getName()));
                }
            }
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
            }
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return instance;
    }

添加例子

@ComponentXzc
@ScopeXzc(value = "singleton")
public class OrderService{
    void test(){
        System.out.println("OrderService test");
    }
}

在userService里面注入OrderService 

@ComponentXzc
//@ScopeXzc(value = "singleton")
@ScopeXzc(value = "prototype")
public class UserService implements UserInterface{

    @Autowired
    OrderService orderService;

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

依赖注入成功

spring生成不重复数字ID 重写spring,spring生成不重复数字ID 重写spring_spring_03,第3张

存在的问题循环依赖

spring生成不重复数字ID 重写spring,spring生成不重复数字ID 重写spring_spring生成不重复数字ID_04,第4张

未完待续

4.实现AOP功能

首先我们定义后置处理器


https://www.xamrdz.com/lan/5v31924600.html

相关文章: