0
点赞
收藏
分享

微信扫一扫

手写 Spring 之 Autowired、Component、ComponentScan 注解功能模拟

独兜曲 2022-04-14 阅读 38

手写 Spring 之 Autowired、Component、ComponentScan 注解功能模拟

一、创建一个空的项目

完成后的工程目录如图:
在这里插入图片描述

二、代码说明

容器定义

package com.demo.spring;


import com.demo.spring.ann.Autowired;
import com.demo.spring.ann.Component;
import com.demo.spring.ann.ComponentScan;
import com.demo.spring.ann.Scope;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

/**
 * Description: Spring 容器
 *
 * @Author: zhx & moon hongxu_1234@163.com
 * @Date: 2022-04-13 20:06
 * @version: V1.0.0
 */
public class SpringApplicationContext {

    /**
     * 启动类
     */
    private Class appClass;

    /**
     * 扫描结果池
     */
    private static Map<String,BeanDefinition> beanMap = new HashMap<>(16);

    /**
     * 单例池
     */
    private static Map<String,Object> singletonMap = new HashMap<>(16);

    /**
     * 构造容器 扫描注解并实例化Bean
     * @param appClass
     */
    public SpringApplicationContext(Class appClass)  {
        this.appClass = appClass;
        //扫描
        scan();
        //生成
        for (String k:beanMap.keySet()){
            singletonMap.put(k,createBean(k, beanMap.get(k)));
        }
    }

    /**
     * 获取Bean实例 不存在则抛出空指针异常
     * @param beanName
     * @return
     */
    public Object getBean(String beanName){
        if (beanMap.containsKey(beanName)){
            BeanDefinition beanDefinition = beanMap.get(beanName);
            if ("prototype".equals(beanDefinition.getScope())){
                return createBean(beanName,beanDefinition);
            }else{
                return singletonMap.get(beanName);
            }
        }
        throw new NullPointerException();
    }


    /**
     * 扫描需要在启动时生成Bean配置的类
     */
    private void scan(){
        if (appClass.isAnnotationPresent(ComponentScan.class)){
            ComponentScan scan = (ComponentScan) appClass.getAnnotation(ComponentScan.class);
            String scanPath = scan.value();
            scanPath = scanPath.replace(".","/");
            ClassLoader classLoader = SpringApplicationContext.class.getClassLoader();
            URL url = classLoader.getResource(scanPath);
            File file = new File(url.getFile());
            //实际可能需要递归处理
            if (file.isDirectory()){
                for (File f:file.listFiles()){
                    String absolutePath = f.getAbsolutePath();
                    absolutePath = absolutePath.substring(absolutePath.indexOf("com"),absolutePath.indexOf(".class")).replace("\\",".");
                    try {
                        Class clazz = classLoader.loadClass(absolutePath);
                        if (clazz.isAnnotationPresent(Component.class)){
                            //获取Bean名称
                            Component component = (Component) clazz.getAnnotation(Component.class);
                            String beanName = component.value();
                            if ("".equals(beanName)){
                                beanName = Introspector.decapitalize(clazz.getSimpleName());
                            }
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setScope("");
                            beanDefinition.setType(clazz);
                            //判断单例还是原型(多例)
                            if (clazz.isAnnotationPresent(Scope.class)){
                                Scope scope = (Scope) clazz.getAnnotation(Scope.class);
                                String model = scope.value();
                                if ("prototype".equals(model)){
                                    beanDefinition.setScope("prototype");
                                }
                            }
                            beanMap.put(beanName,beanDefinition);
                        }
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 创建Bean 当前只处理无参构造
     * @return
     */
    public Object createBean(String beanName,BeanDefinition beanDefinition){
        Class clazz = beanDefinition.getType();
        try {
            Object bean = clazz.getConstructor().newInstance();
            for (Field field:clazz.getDeclaredFields()){
                if (field.isAnnotationPresent(Autowired.class)){
                    String autowiredBeanName = field.getName();
                    field.setAccessible(true);
                    field.set(bean,getBean(autowiredBeanName));
                }
            }
            return bean;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

注解

1.Autowired

package com.demo.spring.ann;

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

/**
 * Description: 依赖注入注解
 *
 * @Author: zhx & moon hongxu_1234@163.com
 * @Date: 2022-04-13 22:32
 * @version: V1.0.0
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {

}

2.Component

package com.demo.spring.ann;

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

/**
 * Description: 配置类注解
 *
 * @Author: zhx & moon hongxu_1234@163.com
 * @Date: 2022-04-13 20:19
 * @version: V1.0.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {

    String value() default "";

}

3.ComponentScan

package com.demo.spring.ann;

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

/**
 * Description: 注解扫描
 *
 * @Author: zhx & moon hongxu_1234@163.com
 * @Date: 2022-04-13 22:30
 * @version: V1.0.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ComponentScan {

    String value() default "";

}

4.Scope

package com.demo.spring.ann;

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

/**
 * Description: 作用域
 *
 * @Author: zhx & moon hongxu_1234@163.com
 * @Date: 2022-04-13 23:05
 * @version: V1.0.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Scope {

    String value() default "";

}

测试实体

1.Student

package com.demo.test.entity;

import com.demo.spring.ann.Component;
import com.demo.spring.ann.Scope;

/**
 * Description: 学生
 *
 * @Author: zhx & moon hongxu_1234@163.com
 * @Date: 2022-04-13 23:43
 * @version: V1.0.0
 */
@Component
@Scope("prototype")
public class Student {

}

2.Teacher

package com.demo.test.entity;

import com.demo.spring.ann.Component;

/**
 * Description: 老师
 *
 * @Author: zhx & moon hongxu_1234@163.com
 * @Date: 2022-04-13 23:48
 * @version: V1.0.0
 */
@Component
public class Teacher {
}

3.User

package com.demo.test.entity;

import com.demo.spring.ann.Autowired;
import com.demo.spring.ann.Component;

/**
 * Description: 测试实体
 *
 * @Author: zhx & moon hongxu_1234@163.com
 * @Date: 2022-04-13 22:31
 * @version: V1.0.0
 */
@Component("user")
public class User {

    @Autowired
    Teacher teacher;

    public void test(){
        System.out.println("张三");
        System.out.println(teacher);
    }

}

启动类

1.AppConfig

package com.demo.test;

import com.demo.spring.ann.ComponentScan;

/**
 * Description: 启动类
 *
 * @Author: zhx & moon hongxu_1234@163.com
 * @Date: 2022-04-13 22:35
 * @version: V1.0.0
 */
@ComponentScan("com.demo.test.entity")
public class AppConfig {

}

测试类

1.Test

package com.demo.test;

import com.demo.spring.SpringApplicationContext;
import com.demo.test.entity.User;

/**
 * Description: 测试类
 *
 * @Author: zhx & moon hongxu_1234@163.com
 * @Date: 2022-04-13 20:04
 * @version: V1.0.0
 */
public class Test {
    public static void main(String[] args) {

        SpringApplicationContext applicationContext = new SpringApplicationContext(AppConfig.class);
        System.out.println("单例--------------------");
        System.out.println(applicationContext.getBean("user"));
        System.out.println(applicationContext.getBean("user"));
        System.out.println(applicationContext.getBean("user"));
        System.out.println("原型--------------------");
        System.out.println(applicationContext.getBean("student"));
        System.out.println(applicationContext.getBean("student"));
        System.out.println("注入--------------------");
        System.out.println(applicationContext.getBean("teacher"));
        User user = (User) applicationContext.getBean("user");
        user.test();
    }
}

三、结果

Connected to the target VM, address: '127.0.0.1:52335', transport: 'socket'
Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended
单例--------------------
com.demo.test.entity.User@27fa135a
com.demo.test.entity.User@27fa135a
com.demo.test.entity.User@27fa135a
原型--------------------
com.demo.test.entity.Student@46f7f36a
com.demo.test.entity.Student@421faab1
注入--------------------
com.demo.test.entity.Teacher@2b71fc7e
张三
com.demo.test.entity.Teacher@2b71fc7e
Disconnected from the target VM, address: '127.0.0.1:52335', transport: 'socket'

Process finished with exit code 0
举报

相关推荐

0 条评论