手写Spring(一)- 扫描并通过容器创建实例 - @Component、@ComponentScann、@Scope、Spring容器、单例和原型

一:创建容器骨架(逐步完善容器类)

package com.zhw.spring;
import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URL;
public class ClassPathApplication {
    private Class AppConfig;
    public ClassPathApplication(Class appConfig) throws Exception {
        AppConfig = appConfig;
    }
       public  Object getBean(String beanName) {
       return null;
    }
}

二:定义@component、@componentScann、@Scope注解
1,@component注解,标记该类的实例需要被Spring容器管理

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

2,@componentScann注解,指定扫描器扫描的范围;只有在Spring的扫描器的扫描范围之内并且有@component、@Service、@Repository等标记类才会被扫描到并且Spring管理该类的实例

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

3,@Scope注解,标记在需要被Spring容器管理的类的上面,指定该类在创建对象时是创建单例的的还是原型的

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

三:扫描需要容器管理实例的类
1,配置类,@component注解标记了扫描的范围

package com.zhw.config;
import com.zhw.spring.ComponentScann;
@ComponentScann("com.zhw.service")
public class AppConfig {
}

2,完善容器类ClassPathApplication,准确扫描到需要被容器管理的类

package com.zhw.spring;
import java.io.File;
import java.lang.annotation.Annotation;
import java.net.URL;
public class ClassPathApplication {
    private Class AppConfig;
    public ClassPathApplication(Class appConfig) throws Exception {
        AppConfig = appConfig;
        // 扫描AppConfig配置类指定的扫描范围
        scanner(appConfig);
    }

    private void scanner(Class appConfig) throws ClassNotFoundException {
        ComponentScann componentScannAnnotation = (ComponentScann)appConfig.getDeclaredAnnotation(ComponentScann.class);
        // value是需要扫描的范围
        String value = componentScannAnnotation.value();
        // 由于在磁盘中都是以文件的形式存贮
        String path = value.replace('.', '/');
        // 该path下所有资源
        ClassLoader classLoader = ClassPathApplication.class.getClassLoader();
        URL resource = classLoader.getResource(path);
        File file = new File(resource.getFile());
        // 判断该文件是否为文件夹
        if (file.isDirectory()) {
            // 该文件夹下所有文件
            File[] files = file.listFiles();
            for (File file1 : files) {
                // 绝对路径
                String absolutePath = file1.getAbsolutePath();
                // 判断是否是.java编译之后的.class文件
                if(absolutePath.endsWith(".class")){
                    String classNamePre = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
                    // 类的全限定名
                    String className = classNamePre.replace('\\', '.');
                    Class<?> aClass = classLoader.loadClass(className);
                    Component componentAnnotation = aClass.getDeclaredAnnotation(Component.class);
                    if(componentAnnotation.value().length()>0){
                        // className ->该类的实例应该被加入容器
                       
                    }
                }
            }
        }

    }

    public  Object getBean(String beanName) {
        return null;
    }
}

四:根据类的作用域(Scope),创建实例;BeanDefinition类的使用
1,创建BeanDefinition类定义Bean

package com.zhw.spring;
public class BeanDefinition {
    private Class aClass;
    private String scope;
    public Class getaClass() {
        return aClass;
    }
    public void setaClass(Class aClass) {
        this.aClass = aClass;
    }
    public String getScope() {
        return scope;
    }
    public void setScope(String scope) {
        this.scope = scope;
    }
}

2,完善容器类ClassPathApplication,根据作用域创建实例并加入容器

package com.zhw.spring;

import java.io.File;
import java.net.URL;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class ClassPathApplication {
    private Class AppConfig;
    // 存放所有 BeanDefinition 对象的map
    Map<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
    // 单例池
    Map<String,Object> singletonMap = new ConcurrentHashMap<>();
    public ClassPathApplication(Class appConfig) throws Exception {
        AppConfig = appConfig;
        // 扫描AppConfig配置类指定的扫描范围
        scanner(appConfig);
        // 经过扫描之后,所有需要创建对象的类的信息都在 beanDefinitionMap 中
        Set<Map.Entry<String, BeanDefinition>> beanDefinitionEntrySets = beanDefinitionMap.entrySet();
        for (Map.Entry<String, BeanDefinition> beanDefinitionEntrySet : beanDefinitionEntrySets) {
            String className = beanDefinitionEntrySet.getKey();
            BeanDefinition beanDefinition = beanDefinitionEntrySet.getValue();
            if ("singleton".equals(beanDefinition.getScope())){
                // 创建该类的对象并放入单例池中
                Object bean = createBean(beanDefinition);
                singletonMap.put(className,bean);
            }
        }
    }

    private void scanner(Class appConfig) throws ClassNotFoundException {
        ComponentScann componentScannAnnotation = (ComponentScann)appConfig.getDeclaredAnnotation(ComponentScann.class);
        // value是需要扫描的范围
        String value = componentScannAnnotation.value();
        // 由于在磁盘中都是以文件的形式存贮
        String path = value.replace('.', '/');
        // 该path下所有资源
        ClassLoader classLoader = ClassPathApplication.class.getClassLoader();
        URL resource = classLoader.getResource(path);
        File file = new File(resource.getFile());
        // 判断该文件是否为文件夹
        if (file.isDirectory()) {
            // 该文件夹下所有文件
            File[] files = file.listFiles();
            for (File file1 : files) {
                // 绝对路径
                String absolutePath = file1.getAbsolutePath();
                // 判断是否是.java编译之后的.class文件
                if(absolutePath.endsWith(".class")){
                    String classNamePre = absolutePath.substring(absolutePath.indexOf("com"), absolutePath.indexOf(".class"));
                    // 类的全限定名
                    String className = classNamePre.replace('\\', '.');
                    Class<?> aClass = classLoader.loadClass(className);
                    Component componentAnnotation = aClass.getDeclaredAnnotation(Component.class);
                    if(componentAnnotation.value().length()>0){
                        // className ->该类的实例应该被加入容器
                        BeanDefinition beanDefinition = new BeanDefinition();
                        beanDefinition.setaClass(aClass);
                        if(aClass.isAnnotationPresent(Scope.class)){
                            String value1 = aClass.getDeclaredAnnotation(Scope.class).value();
                            beanDefinition.setScope(value1);
                        } else {
                          // 没有标注@Scope注解,就是默认的单例
                          beanDefinition.setScope("singleton");
                        }
                        beanDefinitionMap.put(className,beanDefinition);
                    }
                }
            }
        }

    }
    // 创建实例的方法
    private Object createBean(BeanDefinition beanDefinition) throws InstantiationException, IllegalAccessException {
        Object object = beanDefinition.getaClass().newInstance();
        return object;
    }

    public  Object getBean(String beanName) throws InstantiationException, IllegalAccessException {
        Object object = null;
        // 判断 beanName 是否被扫描到
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if(beanDefinition!=null){
            if("singleton".equals(beanDefinition.getScope())){
                return singletonMap.get(beanName);
            }else{
                object = beanDefinition.getaClass().newInstance();
            }
        }
        return object;
    }
}

3,测试
3.1 测试(单例)

package com.zhw.service;
import com.zhw.spring.Component;
@Component(value = "quazrtService")
public class QuazrtService {

}

测试
package com.zhw.test;
import com.zhw.config.AppConfig;
import com.zhw.spring.ClassPathApplication;
import com.zhw.spring.ZhanghwApplicationContext;
public class ZhanghwApplicationContextTest {
    public static void main(String[] args) throws Exception {
        ClassPathApplication classPathApplication = new ClassPathApplication(AppConfig.class);
        Object object1 = classPathApplication.getBean("com.zhw.service.QuazrtService");
        Object object2 = classPathApplication.getBean("com.zhw.service.QuazrtService");
        Object object3 = classPathApplication.getBean("com.zhw.service.QuazrtService");
        Object object4 = classPathApplication.getBean("com.zhw.service.QuazrtService");
        System.out.println(object1);
        System.out.println(object2);
        System.out.println(object3);
        System.out.println(object4);
    }
}

结果
"C:\Program Files\Java\jdk1.8.0_172\bin\java.exe" "-javaagent:D:\IntelliJ IDEA spring\target\classes" com.zhw.test.ZhanghwApplicationContextTest
com.zhw.service.QuazrtService@5e2de80c
com.zhw.service.QuazrtService@5e2de80c
com.zhw.service.QuazrtService@5e2de80c
com.zhw.service.QuazrtService@5e2de80c

Process finished with exit code 0

3.2 测试(prototype原型)

package com.zhw.service;
import com.zhw.spring.Component;
import com.zhw.spring.Scope;
@Component(value = "quazrtService")
@Scope(value = "prototype")
public class QuazrtService {

}

结果
"C:\Program Files\Java\jdk1.8.0_172\bin\java.exe" "-javaagent:D:\IntelliJ IDEA 2021.1.3\lib\idea_rt.jar=10780:D:\IntelliJ IDEA 2021.1.3\bin" -
com.zhw.service.QuazrtService@1d44bcfa
com.zhw.service.QuazrtService@266474c2
com.zhw.service.QuazrtService@6f94fa3e
com.zhw.service.QuazrtService@5e481248

Process finished with exit code 0
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值