Mini-Spring之依赖注入

引言

我们上一篇文章中,已经实现了简单类的注入功能,这篇文章主要是为了完成复杂类的注入功能。废话少说,我们开始出发。

本文所有的代码都在这个项目工程里,大家需要的时候可以随时取用。传送门

补全bean名称生成

在之前的代码中,bean的名称一直都是取@Component注解中的值,但是这个值可以为空的,我们没有处理这个分支下的情况,这次我们就进行一个补全,具体代码如下:

Component componentAnnotation = clazz.getAnnotation(Component.class);
String beanName = componentAnnotation.value();
//只需要在原来的代码中增加一段这样的代码
if("".equals(beanName)){
  //transfer name ,eg: Service->service SService->SService, SerR->serR
  //这里是直接取java.beans包下的一个方法,目的是将首字母小写。
  beanName = Introspector.decapitalize(clazz.getSimpleName());
}

依赖注入

回到正题,在Spring中依赖注入需要一个注解,用它实例化需要依赖的类。因此,我们也需要创建一个注解,代码如下:

package com.zhu.spring;

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

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
}

准备工作做完了,我们需要思考一下,在哪里去创建这个依赖呢?

没错,就是在创建bean的时候,我们需要创建这个依赖的bean,也就是在之前的createBean方法中去创建,具体代码如下:

private Object createBean(String beanName, BeanDefinition beanDefinition){

        Class clazz = beanDefinition.getType();

        try {
            Object instance = clazz.getConstructor().newInstance();
                        // 新增的代码,查找类的所有变量,判断是否有Autowired注解修饰的类
            // simple dependency injection
            for (Field field : clazz.getDeclaredFields()) {
                                    
                if (field.isAnnotationPresent(Autowired.class)) {
                      //有Autowired修饰的类,即需要注入的类
                    //change true ,can assign private
                    field.setAccessible(true);
                      //获取字段的名称作为类名称
                    String fieldName = field.getName();
                      //直接调用getBean方法查询之前是否有创建过的bean,没有就新建,具体看一下实现
                    Object bean = getBean(fieldName);
                      //将bean设置进去
                    field.set(instance, bean);
                }
            }
            return instance;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return null;
    }

我们可以做个测试,先创建一个OrderService类,然后在UserService中注入它,并打印结果,具体如下:

@Component
@Scope("singleton")
public class OrderService {
}

@Component
@Scope("singleton")
public class UserService {

    @Autowired
    private OrderService orderService;

    public void test(){
        System.out.println(orderService);
    }
}


public class Test {
    public static void main(String[] args) {
        MiniSpringApplicationContext miniSpringApplicationContext = new MiniSpringApplicationContext(AppConfig.class);

        UserService userService = (UserService)miniSpringApplicationContext.getBean("userService");
        userService.test();

    }
}
//打印结果:
//com.zhu.service.OrderService@610455d6

自此,我们解决了我们依赖注入的问题,可以在代码中写更加复杂的bean了。