在使用springboot过程中,想使用jdbc模板,就是直接在service层注入一个jdbcTemplate属性,然后直接使用,但是又想封装一下,就创建一个类,类中有jdbcTemplate属性,然后再service中调用我封装的jdbc,刚开始没有封装方法的情况下,想在service中直接想注入我的类,然后调用我的类中的jdbc,什么注解都标注好了,结果一直空指针异常,还以为不好使呢,其实这里面有个很大的问题,就是注解注入的对象和new的对象到底有啥区别;
我们知道,new一个对象的时候,初始化顺序是,父类静态块>子类静态块> 父类属性(先系统默认值,后直接你赋予的值) >父类构造器>子类属性>子类构造器
但是当有个注解在属性上的时候,会是啥情况呢?
-
@Repository
-
public class A {
-
/**
-
* 属性初始化的顺序是在构造器之前,编译器也会先设置默认值,然后赋予指定值
-
* 但是当该类的实例是spring注解的注入方式,那么被指定的值不会被赋值
-
*/
-
public int aa=1;//定义到C的前面,会被先于C初始化
-
public String as;//如果该类的对象是springMVC注解注入的方式,那么这个属性默认是null,即使赋值,也是空
-
@Resource
-
public C c ; //不会被初始化 如果 = new C(); 会先于aa和aaa初始化
-
public int aaa=2;//定义到C的后面,但是 C不会被初始化
-
public void run(){
-
System.out.println("aaaaa");
-
c.foo();
-
}
-
}
-
@RestController
-
public class B {
-
@Resource
-
public A a = new A();
-
@RequestMapping("/B")
-
public void test1() {
-
System.out.println(a.as);//如果是注解注入A对象,注意此时A的初始化 只是简单的调用A的空构造函数,A中的属性默认都是默认值(int是0,类属性是null),A中的属性如果自定义了赋值,也不会被使用。
-
System.out.println(a.aa);
-
//a.c.foo();
-
System.out.println(a.c);
-
System.out.println(a.aaa);
-
}
-
}
-
@Component
-
public class C {
-
public C() {
-
System.out.println("C..init..");
-
}
-
public void foo(){
-
System.out.println("cccc");
-
}
-
}
结论:注入的对象,只会调用空参构造函数,且这个对象的所有属性都是默认值,自己手动赋予的值不会被使用,
所以在A中的C类,在B中调用A的时候,创建的A对象的属性都是默认值,所以A对象虽然有了,但是A的属性C却是null,所以在B中直接this.a.c.method()是会报null指针异常的,且是c是null的发生原因。
解决方式:C在A中添加get方法,然后B中使用a.getC()即可获得c的对象,且c的对象也是spring注入的。
备注:以上结论和说明,只是个人总结,包括new一个对象初始化顺序,可能不严谨,没有时间验证,以后会完善