@Autowired注解在抽象类中失效的原因及解决
作者:jy的blog
@Autowired注解在抽象类中失效
最近在工作中遇到这个问题,在抽象类中使用Autowired这个注解,注入mybatis的dao时,总是出现空指针异常,通过日志的打印,发现是这个dao注入失败为空。然后通过new出spring上下文对象,再去调用getBean()方法,获取到这个注入的dao,这样是可行的,但是总是觉得这不是最佳实践,一定有比这个更加优雅的方式能解决这个问题。
我们来还原一下这个问题:
1.定义一个抽象类
声明为spring组件,在其中自动装配另一个bean:
@Component public abstract class BaseService { @Autowired Dao dao; }
2.然后在他的子类中使用这个自动装配的对象
@Component public class myService extends BaseService{ public void print(){ //运行时为null System.out.print(dao.toString()); } }
在我们实例化子类对象的时候,抽象父类不能实例化,因为spring注入的是实例对象,而不是类,所以spring不会将dao自动装配注入到一个实例中。但是我们通过在在抽象类中获取的上下文对象中却可以拿到dao,因为这个上下文对象
是我们自己手动new出来的,不是spring通过反射注入到对象中去的。因此这种方案是可行的。
下面介绍一种更优雅的解决方案:
1.同样是定义一个抽象类
public class BaseService { Dao dao; }
2.在子类中使用注解
@Component public class myService extends BaseService{ //Autowired修饰方法时,根据方法参数类型判断实例化哪个类 @Autowired public void printDao(Dao dao){ super.dao = dao;//父类属性注入 } public void print(){ System.out.print(dao.toString()); } }
这样写是不是要比我们直接去new applicationContext更加优雅呢?
在抽象类中使用@Autowired
1.简介
在本快速教程中,我们将说明如何在抽象类中使用 @Autowired 自动装配注解。
我们将 @Autowired 应用于 abstract 抽象类,并关注此时要考虑的重点。
2.Setter 方式注入
我们可以在设置方法上使用_@Autowired_:
public abstract class BallService { private LogRepository logRepository; @Autowired public final void setLogRepository(LogRepository logRepository) { this.logRepository = logRepository; } }
当我们使用_@Autowired_上setter方法,我们应该用final 关键字,这样子类便不能覆盖setter方法。否则,注解将无法正常运行。
3.构造函数注入
我们不能在抽象类的构造函数上使用_@Autowired_。
Spring 不会在抽象类的构造函数上解析 @Autowired 注解。子类应为 super 构造函数提供必要的参数。
相反,我们应该在子类的构造函数上使用_@Autowired_:
public abstract class BallService { private RuleRepository ruleRepository; public BallService(RuleRepository ruleRepository) { this.ruleRepository = ruleRepository; } } @Component public class BasketballService extends BallService { @Autowired public BasketballService(RuleRepository ruleRepository) { super(ruleRepository); } }
4.备忘单
让我们总结一些要记住的规则。
首先,抽象类不会进行组件扫描,因为没有具体的子类就无法实例化。
其次,在抽象类中可以进行setter注入,但是如果不对setter方法使用_final_关键字,因而存在一定误用的风险。如果子类覆盖 setter 方法,则应用程序可能不能正常运行。
第三,由于 Spring 在抽象类中不支持构造函数注入,因此通常应该让具体的子类提供构造函数参数。这意味着我们需要在具体子类中依赖构造函数注入。
最后,将构造函数注入用于必需的依赖项,并将setter注入用于可选的依赖项是一个很好的经验法则。但是,正如我们可以从抽象类的一些细微差别中看到的那样,通常在这里构造函数注入更为有利。
因此,实际上我们可以说具体的子类控制着它的抽象父类如何获得其依赖项。 Spring 在装配子类时, 会对其依赖进行注入。
5.结论
在本文中,我们练习了在抽象类中使用_@Autowired_,并解释了一些关键点。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。