spring深入

202 阅读2分钟

深入spring,学习注解怎么工作的。类加载器的玩法,内嵌tomcat是怎么一回事。通过细节了解之前从来没关注过的点。

先从ioc聊起

控制反转:对象不是我们new的,对象的属性也不是我们注入的。 依赖注入:属性是框架帮我们注入的。

package com.obsidian.demo.test;

/**
 * 用常用的代码 进入分析
 * 如果没有Spring....
 * @author huoyun
 * @date 2019/7/13-11:43
 */
public class UserController {
    /**
     * 如果没有Spring IOC
     * 这就得 开始new对象了。
     */
    private UserService userService;
}

如果是@AutoWried 是不需要写set方法的。这是通过getDeclaredFields拿到private属性进行注入。 field.setAccessible(true);是能给private属性赋值的原因

/**
 * 手写IOC
 * 这种方式 通过getDeclaredFields  能够拿到private属性 不走set方法 进行属性注入
 * 这也是@AutoWried 的手段
 */
@Test
public void IOCTest() throws Exception {
    // jdk 1.9这么写deprecate 需要去拿 构造器
    UserController userController = UserController.class.newInstance();
    UserService userService = UserService.class.newInstance();
    // 能拿到各种修饰符的
//        Field[] declaredFields = UserController.class.getDeclaredFields();
//        Arrays.stream(declaredFields).forEach(System.out::println);//private com.obsidian.demo.test.UserService com.obsidian.demo.test.UserController.userService
    // 简单来说 已经知道属性是啥了 直接根据名字拿
    Field field = UserController.class.getDeclaredField("userService");
    System.out.println("userService:" + field);//userService:private com.obsidian.demo.test.UserService com.obsidian.demo.test.UserController.userService

    // false 是不能给private的属性赋值的 改成true
    field.setAccessible(true);
    // 第一个参数 是给那个类的field 赋值  第二个参数 是value
    field.set(userController, userService);

    // 这时候发现已经注入进去了
    System.out.println(ToStringBuilder.reflectionToString(userController));
}

还可以拿到field的名字首字母大写然后在前面拼接上set,invoke这个方法。个人觉得无意义上面的才是用的最多的。 自己写了一个@Autowired 来实现给带@Autowired的属性进行注入

@Test
public void IOCTestWithAnnotation() {
    UserController userController = new UserController();

    // all fields
    Field[] declaredFields = UserController.class.getDeclaredFields();
    Arrays.stream(declaredFields).forEach(item -> {
        // 判断 有没有Autowired注解
        if (item.isAnnotationPresent(Autowired.class)) {
            // 拿到field的类型
            Class<?> type = item.getType();
            try {
                // 根据拿出的类型进行实例化
                Object instance = type.newInstance();
                // 可以对private进行访问 然后赋值
                item.setAccessible(true);
                item.set(userController, instance);
            } catch (InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    });

    System.out.println(ToStringBuilder.reflectionToString(userController));
}