栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

手写Spring----包扫描和创建单例bean

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

手写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 singletonObjects = new ConcurrentHashMap<>();
    private ConcurrentHashMap beanDefiniationMap = new ConcurrentHashMap<>();//bean的定义

    public cjwApplicationContext(Class configClass) throws ClassNotFoundException {
        this.configClass = configClass;
        //解析配置类
        //ComponentScan注解------》扫描路径-----》扫描具体事情---->Beandefinition--->BeanDefinitionMap
        //对spring而言对当前传递的类是否有spring的相应注解
        scan(configClass);
        for (Map.Entry 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);
            }
        }
    }

    
    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(".", "/");
        
        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:ideaWorkVspringdemotargetclassescomexamplespringdemotestserviceUserService.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 单例池
        Object userService1 = context.getBean("userService");//map 单例池
        Object userService2 = context.getBean("userService");//map 单例池
        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 - 博客园

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/726978.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号