手写简化Spring IOC容器

BeanDefinition,里面有beanName和beanClass,到时候可以封装到这个类里面

@Data
@AllArgsConstructor
@NoArgsConstructor
public class BeanDefinition {
    private String beanName;
    private Class beanClass;
}

最重要的类MyAnnotationConfigApplicationContext

在他的这个构造函数里,我们首先先根据他传入的包的名字,把这个包里面的所有类都扫描一次

Set<BeanDefinition> beanDefinitions = findBeanDefinitions(pack);

findBeanDefinitions函数

首先他要扫描包下面的所有类,然后得到这些类以后,我要去遍历一下,找到添加了注解的类,如果我添加了这个注解的话,返回的值就不是null(Component componentAnnotation = clazz.getAnnotation(Component.class)),接下来的话,判断一下有没有自定义的beanName吧,如果没有的话,我就给他改一下

				//这样子说明我直接就写了component注解而已,后面没给出名字,那我就给他搞个名字
                //名字的话,我把全类名前面的干掉
                //再把Account改成account这样子,比较规范
                if ("".equals(beanName)){
                    String packageName = clazz.getPackage().getName();
                    packageName += ".";
                    String clazzName = clazz.getName();
                    clazzName = clazzName.replaceAll(packageName,"");
                    beanName = clazzName.substring(0,1).toLowerCase()+clazzName.substring(1);
                }

现在我可以把beanName和得到的类封装成前面写下的BeanDefinition了,然后放进集合里面,为什么要集合呢,因为要去重.

 				//beanDefinitions集合放入通过封装的BeanDefinition对象
                //BeanDefinition里面的field有bean的名字和类,现在封装好放进集合
                //之所以选择set,是因为要去重,有一个就足够了
                beanDefinitions.add(new BeanDefinition(beanName,clazz));

下面是完整的该函数代码

public Set<BeanDefinition> findBeanDefinitions(String pack){
        Set<BeanDefinition> beanDefinitions = new HashSet<>();
        //获取包下面的所有类
        Set<Class<?>> classes = MyTools.getClasses(pack);
        //遍历这些类,找到添加了注解的类
        Iterator<Class<?>> iterator = classes.iterator();
        while (iterator.hasNext()){
            Class<?> clazz = iterator.next();
            //返回对应注解的Class对象
            Component componentAnnotation = clazz.getAnnotation(Component.class);
            if (componentAnnotation!=null){
                //获取component注解的值
                String beanName = componentAnnotation.value();
                //这样子说明我直接就写了component注解而已,后面没给出名字,那我就给他搞个名字
                //名字的话,我把全类名前面的干掉
                //再把Account改成account这样子,比较规范
                if ("".equals(beanName)){
                    String packageName = clazz.getPackage().getName();
                    packageName += ".";
                    String clazzName = clazz.getName();
                    clazzName = clazzName.replaceAll(packageName,"");
                    beanName = clazzName.substring(0,1).toLowerCase()+clazzName.substring(1);
                }
                //beanDefinitions集合放入通过封装的BeanDefinition对象
                //BeanDefinition里面的field有bean的名字和类,现在封装好放进集合
                //之所以选择set,是因为要去重,有一个就足够了
                beanDefinitions.add(new BeanDefinition(beanName,clazz));
            }
        }
        return beanDefinitions;
    }

找到所有bean放进集合以后,下一步要做的呢,就是放进ioc容器里面,ioc容器这里用的是

private Map<String,Object> ioc = new HashMap<>();

接下来从集合里面拿出我的BeanDefinition,然后分别拿出beanName和beanCLass,通过类对象的getConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象。

Object object = clazz.getConstructor().newInstance();

clazz.getDeclaredFields()拿到所有的字段,遍历所有的字段,老样子判断添加了@Value注解的字段
拿到字段名字以后去制作set方法

						String value = valueAnnotation.value();
                        //拿到字段名字
                        String fieldName = declaredField.getName();
                        //要去做这个字段的set方法
                        String methodName = "set" +fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
                        Method method = clazz.getMethod(methodName,declaredField.getType());

要完成类型赋值的话,得转一下类型,不然的话到时候直接就报错了,类型不匹配

switch (declaredField.getType().getName()) {
                            case "java.lang.Integer":
                                val = Integer.parseInt(value);
                                break;
                            case "java.lang.String":
                                val = value;
                                break;
                            case "java.lang.Float":
                                val = Float.parseFloat(value);
                                break;
                        }

method.invoke(“要调用的方法的名字所隶属的对象实体”,方法的参数值);

method.invoke(object,val);

搞定之后放进ioc容器了,用beanName去对应

ioc.put(beanName,object);

该函数的代码

public void createBean(Set<BeanDefinition> beanDefinitions){
        Iterator<BeanDefinition> iterator = beanDefinitions.iterator();
        while (iterator.hasNext()) {
            BeanDefinition beanDefinition = iterator.next();
            //从我封装好的对象里面我拿出我的类
            Class clazz = beanDefinition.getBeanClass();
            //从我封装好的对象里面拿出我的beanName
            String beanName = beanDefinition.getBeanName();
            try {
                //通过类对象的getConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象
                Object object = clazz.getConstructor().newInstance();
                //获取此类中的所有字段
                Field[] declaredFields = clazz.getDeclaredFields();

                for (Field declaredField : declaredFields) {
                    //getAnnotation(),如果不是这样的注解,就返回null
                    Value valueAnnotation = declaredField.getAnnotation(Value.class);
                    if (valueAnnotation!=null){
                        String value = valueAnnotation.value();
                        //拿到字段名字
                        String fieldName = declaredField.getName();
                        //要去做这个字段的set方法
                        String methodName = "set" +fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
                        Method method = clazz.getMethod(methodName,declaredField.getType());
                        //完成数据类型转换
                        Object val = null;
                        //拿到数据类型的名字,来完成类型赋值
                        switch (declaredField.getType().getName()) {
                            case "java.lang.Integer":
                                val = Integer.parseInt(value);
                                break;
                            case "java.lang.String":
                                val = value;
                                break;
                            case "java.lang.Float":
                                val = Float.parseFloat(value);
                                break;
                        }
                        //传入值
                        //method.invoke("要调用的方法的名字所隶属的对象实体",方法的参数值);
                        method.invoke(object,val);
                    }
                }

                //搞定之后放进ioc容器了
                ioc.put(beanName,object);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    }

轮到自动装载了

老样子,传过去的还是集合,遍历一次所有的字段,看看有没有@Authwired注解的,看看是不是为null

AutoWired annotation = declaredField.getAnnotation(AutoWired.class);

如果找到了,那就是添加了这个注解的,那我还得再找一下里面有没有@Qualifier注解的

Qualifier qualifier = declaredField.getAnnotation(Qualifier.class);

如果有的话,那我就得通过这个bean的名字去ioc容器拿出来
接下来拿到字段名字和方法等等这些

							String beanName = qualifier.value();
                            //通过bean的名字去ioc容器里面把bean拿出来
                            //ioc容器我用的是hashMap
                            Object bean = getBean(beanName);
                            //拿字段名
                            String fieldName = declaredField.getName();
                            String methodName = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
                            Method method = clazz.getMethod(methodName, declaredField.getType());
							//method.invoke("要调用的方法的名字所隶属的对象实体",方法的参数值);
                            //把另外一个bean传入,不然的话打印出来是null的
                            method.invoke(object,bean);

该函数的完全代码

public void autowireObject(Set<BeanDefinition> beanDefinitions){
        Iterator<BeanDefinition> iterator = beanDefinitions.iterator();
        while (iterator.hasNext()){
            BeanDefinition beanDefinition = iterator.next();
            //因为我的这个beanDefinition对象里面,有一个beanName和一个BeanClass(放类的)
            Class clazz = beanDefinition.getBeanClass();
            //拿出这个类的所有字段
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                //看看这个字段有没有AutoWired这个注解
                AutoWired annotation = declaredField.getAnnotation(AutoWired.class);
                if (annotation!=null){
                    //看看有没有Qualifier这种自定义名字的注解
                    Qualifier qualifier = declaredField.getAnnotation(Qualifier.class);
                    if (qualifier!=null){
                        //我用Qualifier自定义名字了
                        //byName
                        try {
                            String beanName = qualifier.value();
                            //通过bean的名字去ioc容器里面把bean拿出来
                            //ioc容器我用的是hashMap
                            Object bean = getBean(beanName);
                            //拿字段名
                            String fieldName = declaredField.getName();
                            String methodName = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
                            Method method = clazz.getMethod(methodName, declaredField.getType());
                            Object object = getBean(beanDefinition.getBeanName());
                            //传入值
                            //method.invoke("要调用的方法的名字所隶属的对象实体",方法的参数值);
                            //把另外一个bean传入,不然的话打印出来是null的
                            method.invoke(object,bean);
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }else{
                        //byType

                    }
                }
            }
        }
    }

该类的完全代码

```java
public class MyAnnotationConfigApplicationContext {
    private Map<String,Object> ioc = new HashMap<>();
    public MyAnnotationConfigApplicationContext(String pack){
        //遍历包,返回所有的目标类
        Set<BeanDefinition> beanDefinitions = findBeanDefinitions(pack);
        Iterator<BeanDefinition> iterator = beanDefinitions.iterator();

        //根据原材料来创建Bean
        createBean(beanDefinitions);

        //自动装载
        autowireObject(beanDefinitions);
    }

    public void autowireObject(Set<BeanDefinition> beanDefinitions){
        Iterator<BeanDefinition> iterator = beanDefinitions.iterator();
        while (iterator.hasNext()){
            BeanDefinition beanDefinition = iterator.next();
            //因为我的这个beanDefinition对象里面,有一个beanName和一个BeanClass(放类的)
            Class clazz = beanDefinition.getBeanClass();
            //拿出这个类的所有字段
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field declaredField : declaredFields) {
                //看看这个字段有没有AutoWired这个注解
                AutoWired annotation = declaredField.getAnnotation(AutoWired.class);
                if (annotation!=null){
                    //看看有没有Qualifier这种自定义名字的注解
                    Qualifier qualifier = declaredField.getAnnotation(Qualifier.class);
                    if (qualifier!=null){
                        //我用Qualifier自定义名字了
                        //byName
                        try {
                            String beanName = qualifier.value();
                            //通过bean的名字去ioc容器里面把bean拿出来
                            //ioc容器我用的是hashMap
                            Object bean = getBean(beanName);
                            //拿字段名
                            String fieldName = declaredField.getName();
                            String methodName = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
                            Method method = clazz.getMethod(methodName, declaredField.getType());
                            Object object = getBean(beanDefinition.getBeanName());
                            //传入值
                            //method.invoke("要调用的方法的名字所隶属的对象实体",方法的参数值);
                            //把另外一个bean传入,不然的话打印出来是null的
                            method.invoke(object,bean);
                        } catch (NoSuchMethodException e) {
                            e.printStackTrace();
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        } catch (InvocationTargetException e) {
                            e.printStackTrace();
                        }
                    }else{
                        //byType

                    }
                }
            }
        }
    }

    public Object getBean(String beanName){
        return ioc.get(beanName);
    }



    //根据集合来创建bean
    public void createBean(Set<BeanDefinition> beanDefinitions){
        Iterator<BeanDefinition> iterator = beanDefinitions.iterator();
        while (iterator.hasNext()) {
            BeanDefinition beanDefinition = iterator.next();
            //从我封装好的对象里面我拿出我的类
            Class clazz = beanDefinition.getBeanClass();
            //从我封装好的对象里面拿出我的beanName
            String beanName = beanDefinition.getBeanName();
            try {
                //通过类对象的getConstructor()方法获得构造器(Constructor)对象并调用其newInstance()方法创建对象
                Object object = clazz.getConstructor().newInstance();
                //获取此类中的所有字段
                Field[] declaredFields = clazz.getDeclaredFields();

                for (Field declaredField : declaredFields) {
                    //getAnnotation(),如果不是这样的注解,就返回null
                    Value valueAnnotation = declaredField.getAnnotation(Value.class);
                    if (valueAnnotation!=null){
                        String value = valueAnnotation.value();
                        //拿到字段名字
                        String fieldName = declaredField.getName();
                        //要去做这个字段的set方法
                        String methodName = "set" +fieldName.substring(0,1).toUpperCase()+fieldName.substring(1);
                        Method method = clazz.getMethod(methodName,declaredField.getType());
                        //完成数据类型转换
                        Object val = null;
                        //拿到数据类型的名字,来完成类型赋值
                        switch (declaredField.getType().getName()) {
                            case "java.lang.Integer":
                                val = Integer.parseInt(value);
                                break;
                            case "java.lang.String":
                                val = value;
                                break;
                            case "java.lang.Float":
                                val = Float.parseFloat(value);
                                break;
                        }
                        //传入值
                        //method.invoke("要调用的方法的名字所隶属的对象实体",方法的参数值);
                        method.invoke(object,val);
                    }
                }

                //搞定之后放进ioc容器了
                ioc.put(beanName,object);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    }

    public Set<BeanDefinition> findBeanDefinitions(String pack){
        Set<BeanDefinition> beanDefinitions = new HashSet<>();
        //获取包下面的所有类
        Set<Class<?>> classes = MyTools.getClasses(pack);
        //遍历这些类,找到添加了注解的类
        Iterator<Class<?>> iterator = classes.iterator();
        while (iterator.hasNext()){
            Class<?> clazz = iterator.next();
            //返回对应注解的Class对象
            Component componentAnnotation = clazz.getAnnotation(Component.class);
            if (componentAnnotation!=null){
                //获取component注解的值
                String beanName = componentAnnotation.value();
                //这样子说明我直接就写了component注解而已,后面没给出名字,那我就给他搞个名字
                //名字的话,我把全类名前面的干掉
                //再把Account改成account这样子,比较规范
                if ("".equals(beanName)){
                    String packageName = clazz.getPackage().getName();
                    packageName += ".";
                    String clazzName = clazz.getName();
                    clazzName = clazzName.replaceAll(packageName,"");
                    beanName = clazzName.substring(0,1).toLowerCase()+clazzName.substring(1);
                }
                //beanDefinitions集合放入通过封装的BeanDefinition对象
                //BeanDefinition里面的field有bean的名字和类,现在封装好放进集合
                //之所以选择set,是因为要去重,有一个就足够了
                beanDefinitions.add(new BeanDefinition(beanName,clazz));
            }
        }
        return beanDefinitions;
    }
}
## 需要的实体类
```java
@Component
@Data
public class Account {
    @Value("1")
    private Integer id;
    @Value("张三")
    private String name;
    @Value("22")
    private Integer age;

    @AutoWired
    @Qualifier("myOrder")
    private Order order;
}
@Data
@Component("myOrder")
public class Order {
    @Value("jyu")
    private String address;
}

@Component注解

//这种后面是type的,对应的是接口、类、枚举
@Target(ElementType.TYPE)
//runtime,注解不仅被保存到class文件中,就算jvm加载class文件以后,依然存在
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
    String value() default "";
}

@Value注解

//这种后面对应的是field的,对应的是字段和枚举的常量
@Target(ElementType.FIELD)
//runtime,注解不仅被保存到class文件中,就算jvm加载class文件以后,依然存在
@Retention(RetentionPolicy.RUNTIME)
public @interface Value {
    String value();
}

@Qualifier注解

//这种后面对应的是field的,对应的是字段和枚举的常量
@Target(ElementType.FIELD)
//runtime,注解不仅被保存到class文件中,就算jvm加载class文件以后,依然存在
@Retention(RetentionPolicy.RUNTIME)
public @interface Qualifier {
    String value();
}

@AutoWired注解

//这种后面对应的是field的,对应的是字段和枚举的常量
@Target(ElementType.FIELD)
//runtime,注解不仅被保存到class文件中,就算jvm加载class文件以后,依然存在
@Retention(RetentionPolicy.RUNTIME)
public @interface AutoWired {
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值