• spring通过注解方式依赖注入原理 (私有成员属性如何注入)


    一、spring如何创建依赖的对象

      用过spring的都知道我们在dao、service层加上@repository、@Service就能将这两个对象交给spring管理,在下次使用的时候使用@resource 或者@Autowired  就可以拿到而不需要自己再去new了,那么它是如何创建那些加上注解的对象的呢?

    通过JAVA反射拿到无参构造函数

        以下只是举例:

    Constructor<?> constructor = Teacher.class.getConstructor(null);

     可以看到class.getConstructor 可以拿到构造函数,然后再通过constructor.newInstance(null);实例化该对象,如此一来对象便创建好了,有参构造函数也是同理,区别是你要获得它的构造函数参数,然后在getConstructor 中传入参数的类型即可获取对应的构造函数了。

    二、spring创建对象时如何注入依赖的对象 

    现在我们知道spring创建对象是通过反射,那么如何该对象依赖其他对象时是如何操作的呢?举例:

    @Service
    public class Teacher {
    @Resource
    private Student student; public void print(){ if(student!=null){ System.out.println("student name:"+student.getName()); }else{ System.out.println("student is null"); } } }

    我们将Teacher对象交给spring管理了,但是需要在创建Teacher的同时将创建好的Student也赋值进去,可以看到Student对象是private私有的,而且没加get set,也就没法通过反射拿到get set方法并注入它的依赖对象了,这几天一直在查找相关资料终于弄明白了,其实还是反射。。。。。。

    首先通过返回获取成员属性的注解,然后判断注解类型是根据对象类型还是名称注入,到这里都很好理解,关键在于私有对象如何注入,请看以下代码:

    Field[] fields = Teacher.class.getDeclaredFields(); 
            Student student = new Student();
            student.setName("zhangsan");
            Teacher teacher = new Teacher();
            for (Field field : fields) {
                if(field.getType().getName().equals(Student.class.getName())){
                    //关键点!设置私有成员属性为可访问!
                    field.setAccessible(true);
                    //将已创建的对象赋值
                    field.set(teacher, student);
                }
            }
            teacher.print();

    我们假设Student 和Teacher对象都已经由spring创建好了,那么现在Teacher里有Student对象需要依赖注入,于是以上代码使我弄清楚了spring如果注入私有成员属性对象,其重点在于如何不通过get set方法把私有的成员对象赋值进去,关键代码:

    field.setAccessible(true);

    设置私有成员属性可以通过反射获取 ,然后通过

    field.set(teacher, student);

    奖Teacher对象里的成员属性student赋值进去,大功告成!具体的细节实现比如如何判断注解、如何保存SPRING创建的类等等相信大家不用看源码也知道大概是怎么做的了。

    下面附上一段spring 装配对象的源码:

    /**
             * Either this or {@link #getResourceToInject} needs to be overridden.
             */
            protected void inject(Object target, String requestingBeanName, PropertyValues pvs) throws Throwable {
                if (this.isField) {
                    Field field = (Field) this.member;
                    ReflectionUtils.makeAccessible(field);
                    field.set(target, getResourceToInject(target, requestingBeanName));
                }
                else {
                    if (checkPropertySkipping(pvs)) {
                        return;
                    }
                    try {
                        Method method = (Method) this.member;
                        ReflectionUtils.makeAccessible(method);
                        method.invoke(target, getResourceToInject(target, requestingBeanName));
                    }
                    catch (InvocationTargetException ex) {
                        throw ex.getTargetException();
                    }
                }
            }

    其中的

    ReflectionUtils.makeAccessible(field);

    正是设置私有成员属性可以通过反射访问!

    spring创建对象的顺序

    将对象交给spring管理也是就创建顺序的,那就是优先创建无任何依赖、有无参构造函数的对象,只有这样才能确保创建有依赖对象时可以将需要的成员对象注入。

  • 相关阅读:
    跟着思兼学习Klipper(16) Klipper 网页使用摄像头比较全指南
    Ubuntu系统Apache2安装后无法启动,报错apache2.service: Control process exited, code=exited status=1
    正则表达式内容和涵义
    浅谈vue中render函数
    IE浏览器报错TypeError: 对象不支持“includes”属性或方法,其他浏览器正常显示
    vue项目使用svg的步骤和bug过程
    postgresql 数据库备份与恢复
    魔法上网🚁
    [论文] BBR:基于拥塞(而非丢包)的拥塞控制(ACM, 2017)
    NAT 穿透是如何工作的:技术原理及企业级实践(Tailscale, 2020)
  • 原文地址:https://www.cnblogs.com/jack-Star/p/9485403.html
Copyright © 2020-2023  润新知