IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 手写Spring----包扫描和创建单例bean -> 正文阅读

[Java知识库]手写Spring----包扫描和创建单例bean

一、包扫描和创建单例bean案例

  • 创建bean的定义?


public class BeanDefinition {
    private Class clazz;
    private String scope;



    public Class getClazz() {
        return clazz;
    }

    public void setClazz(Class clazz) {
        this.clazz = clazz;
    }

    public String getScope() {
        return scope;
    }

    public void setScope(String scope) {
        this.scope = scope;
    }
}
  • ?创建applicationContext对象 处理包扫描以及创建单例Bean的主要功能
package com.example.spring.demo.spring;
import com.example.spring.demo.test.service.UserService;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class cjwApplicationContext {

    private Class configClass;
    // 单例池
    private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
    private ConcurrentHashMap<String, BeanDefinition> beanDefiniationMap = new ConcurrentHashMap<>();//bean的定义

    public cjwApplicationContext(Class configClass) throws ClassNotFoundException {
        this.configClass = configClass;
        //解析配置类
        //ComponentScan注解------》扫描路径-----》扫描具体事情---->Beandefinition--->BeanDefinitionMap
        //对spring而言对当前传递的类是否有spring的相应注解
        scan(configClass);
        for (Map.Entry<String, BeanDefinition> entry : beanDefiniationMap.entrySet()) {
            String beanName = entry.getKey();
            BeanDefinition beanDefinition = beanDefiniationMap.get(beanName);
            if (beanDefinition.getScope().equals("singleton")) {
                Object bean = createBean(beanDefinition);//单列Bean
                singletonObjects.put(beanName, bean);
            }
        }
    }

    /**
     * 创建单例bean
     * @param beanDefinition
     * @return
     */
    public Object createBean (BeanDefinition beanDefinition)  {
        Class clazz = beanDefinition.getClazz();
        try {
            Object instance = clazz.getDeclaredConstructor().newInstance();
            return instance;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

    //Refactor--->Extact--->Field
    private void scan(Class configClass) throws ClassNotFoundException {
        ComponentScan cs = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
        String path = cs.value();//扫描路径
        System.out.println("path = " + path);
        path = path.replace(".", "/");
        /**
         * 扫描路径 找到ComponentScan注解的类
            根据包名得到类 类加载器
         1、bootstrap --->jre/lib
         2、ext  --->jre/ext/lib
         3、app  --->classpath
         */
        ClassLoader classLoader = cjwApplicationContext.class.getClassLoader();//app
        //URL resource = classLoader.getResource("com/example/spring/demo/test/service");
        URL resource = classLoader.getResource(path);
        File file = new File(resource.getFile());
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (int i = 0; i < files.length; i++) {
               // System.out.println("files[i] = " + files[i]);
               // F:\ideaWorkV\springdemo\target\classes\com\example\spring\demo\test\service\UserService.class
               // classLoader.loadClass("com.example.spring.demo.test.service.UserService");
                String fileName = files[i].getAbsolutePath();
                if (fileName.endsWith(".class")) {
                    String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
                    className = className.replace("\\", ".");
                    System.out.println("className = " + className);
                    Class clazz = classLoader.loadClass(className);
                    if (clazz.isAnnotationPresent(Component.class)) {
                        //  表示当前这个类是一个Bean
                        //  Class--> bean? 解析类,判断当前bean是单例bean,还是prototype的bean
                        //  BeanDefinitBean 解析类生成一个beanDefinitBean
                        Component componentAnnoation = (Component) clazz.getDeclaredAnnotation(Component.class);
                        String beanName = componentAnnoation.value();
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setClazz(clazz);
                        if (clazz.isAnnotationPresent(Scope.class)) {
                            Scope scopeAnnotaion = (Scope)clazz.getDeclaredAnnotation(Scope.class);
                            beanDefinition.setScope(scopeAnnotaion.value());
                        } else {
                            beanDefinition.setScope("singleton");
                        }
                        beanDefiniationMap.put(beanName, beanDefinition);//将bean的定义存储到map中
                    }
                }
            }
        }
    }


    public Object getBean(String beanName) {
        //根据类 判断是否是单例bean还是prototype的bean
        if (beanDefiniationMap.containsKey(beanName)) {
            BeanDefinition beanDefinition = (BeanDefinition) beanDefiniationMap.get(beanName);
            if (beanDefinition.getScope().equals("singleton")) {
                Object o = singletonObjects.get(beanName);
                return o;
            } else {
                // 创建Bean对象
                Object o = createBean(beanDefinition);
                return o;
            }
        } else {
            //不存在对应的bean
            throw new NullPointerException();
        }
    }
}
  • ?自定义component注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
    //service 层 不写 spring解析类名
    String value() default "";
}
  • ?自定义包扫描注解
/**
 * 自定义扫描路径
 *
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {

    //定义扫描路径 一般不用给默认值,使用该注解时候直接设置
    String value() default  "";
}
  • ?自定义域注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
    String value();
}
  • 创建userService,并指定bean的域为原型,(域分为单例和原型两种,单例地址不变化,原型bean地址不断变化)
@Component("userService")
@Scope("prototype")
public class UserService {
}
public class xxxUtil {
}

/**
 *开启事务
 */
@ComponentScan("com.example.spring.demo.test.service")
public class AppConfig {
}
public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        //传入参数为spring的配置文件参数
        cjwApplicationContext context = new cjwApplicationContext(AppConfig.class);
        Object userService = context.getBean("userService");//map<beanName,bean对象> 单例池
        Object userService1 = context.getBean("userService");//map<beanName,bean对象> 单例池
        Object userService2 = context.getBean("userService");//map<beanName,bean对象> 单例池
        System.out.println("userService = " + userService);
        System.out.println("userService1 = " + userService1);
        System.out.println("userService2 = " + userService2);
    }
}

二、相应的知识点

  • 类加载?

根据包名得到类 类加载器 以及对应的扫描路径位置

1、bootstrap --->jre/lib

2、ext --->jre/ext/lib

3、app --->classpath

  • 相应注解理解

@Retention

source:注解只保留在源文件,当Java文件编译成class文件的时候,注解被遗弃;被编译器忽略

class:注解被保留到class文件,但jvm加载class文件时候被遗弃,这是默认的生命周期

runtime:注解不仅被保存到class文件中,jvm加载class文件之后,仍然存在

这3个生命周期分别对应于:Java源文件(.java文件) ---> .class文件?--->?内存中的字节码。

@Target:

   @Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、
类型成员(方法、构造方法、成员变量、枚举值)、
方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

?

参考链接:深入理解Java类加载 - czwbig - 博客园

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-02-05 21:35:51  更:2022-02-05 21:37:15 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:44:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码