Spring 父类变量注入失败的解决

 更新时间:2021年09月22日 12:01:46   作者:长风2015  
这篇文章主要介绍了Spring 父类变量注入失败的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

Spring 父类变量注入失败

昨天遇到一个Action里面Service注入失败,换种说法应该说是根本没有发生注入,本来很简单的一个问题,但由于在项目中多个Action进行了继承,才最终导致了这个看似奇怪的问题。

下面小记下这个过程

收到同事问题,“有个Action请求一直调用报控指针,service一直是空的导致的!”

初步看了代码及配置,没有发现什么问题,起初怀疑是Action没有get方法所致,然后加上仍然无效;然后单步做了各种变量名的替换,一直一样问题 ,这过程中一直关注java代码确忽略了页面请求,通过页面请求发现代码真正逻辑是页面请求了一个子类Action的方法,而这个方法里面调用了父类的一个方法,此时父类里面的Service一直无法注入,对于上面所提的这种需求,实际上是需要在子类做Spring注入的同时也进行父类的Spring注入,那么这种需要这样的配置:

<bean id="****Action" class="com.**.**.contrl.**.mgr.action.**Action" scope="prototype" parent="termCommonAction">
  <property name="orderVerifyApiFacade" ref="ord.bizprov.orderVerifyApiFacade"/>
  <property name="orderListQryApiFacade" ref="ord.query.orderListQryApiFacade"/>
  <property name="channelQryApiFacade" ref="cfguse.channel.channelQryApiFacade" />
</bean> 

经过上面的设置以后,请求子类的Action方法,子类方法中调用父类方法时,就不会出现父类不发生注入的问题了。

Spring通过父类注入公用属性的技巧

XML配置方式提取父类

在使用Spring + Hibernate框架,或者SSH2等框架的时候,在开发中只有一个基本的DAO是现在的非常流行的做法。然后,在看过多份这种代码以后,都是在每个业务类中声明了一个DAO属性,并且在Bean配置中,对每个业务类分别注入DAO。具体情形示例如下:

BaseDAO代码:

public class BaseDAO {
 public String service() {
  return "Success!";
 }
}

Services代码:

//第一个业务类
public class ServiceA {
 public String service() {
  return baseDAO.service();
 } 
 protected BaseDAO baseDAO; 
 public void setBaseDAO(BaseDAO baseDAO) {
  this.baseDAO = baseDAO;
 }
}
 
//第二个业务类
public class ServiceB {
 public String service() {
  return baseDAO.service();
 }
 
 protected BaseDAO baseDAO; 
 public void setBaseDAO(BaseDAO baseDAO) {
  this.baseDAO = baseDAO;
 }
}

Spring的Bean配置如下:

<bean id="baseDAO" class="com.watson.BaseDAO" />
<bean id="serviceA" class="com.watson.ServiceA">
 <property name="baseDAO" ref="baseDAO" />
</bean>
<bean id="serviceB" class="com.watson.ServiceB">
 <property name="baseDAO" ref="baseDAO" />
</bean>

这样的做法是现在的主流。这样做不是说那里错了,还是那句老话:这样做肯定不优美,谁让人有时候是一根筋呢?

能够想到的办法是用一个父类来包含一些业务层公用的业务逻辑和属性。所以可以将上面的代码和配置。

Services代码改写如下:

//所有业务类的父类
public class BaseService {
 protected BaseDAO baseDAO; 
 public void setBaseDAO(BaseDAO baseDAO) {
  this.baseDAO = baseDAO;
 }
}
//第一个业务类
public class ServiceA extends BaseService  {
 public String service() {
  return baseDAO.service();
 }
}
//第二个业务类
public class ServiceB extends BaseService  {
 public String service() {
  return baseDAO.service();
 }
}

Spring的Bean配置改写如下:

<bean id="baseDAO" class="com.watson.BaseDAO" />
<bean id="BaseService" class="com.watson.BaseService" />
 <property name="baseDAO" ref="baseDAO" />
</bean>
<bean id="serviceA" class="com.watson.ServiceA" />
<bean id="serviceB" class="com.watson.ServiceB" />

这样一来是不简洁了很多?尤其在实际项目有太多Bean的时候。然后,这里不会达到我们预想的结果,因为这里会出现如下的错误:

exception:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is

java.lang.NullPointerException

......

root cause:

java.lang.NullPointerException:......

而出错代码就是每个业务中调用baseDAO的那行代码。这说明注入失败了。翻阅Spring的Bean注入详解之后,很快就可以找应该设置子类Bean配置的parent属性。所以这里可以修改设置。

Spring的Bean配置改写如下:

<bean id="baseDAO" class="com.watson.BaseDAO" />
<bean id="BaseService" class="com.watson.BaseService" />
 <property name="baseDAO" ref="baseDAO" />
</bean>
<bean id="serviceA" class="com.watson.ServiceA" parent="baseService" />
<bean id="serviceB" class="com.watson.ServiceB" parent="baseService" />

这个时候再运行,就不会报错了。原理是:在Spring的子类Bean配置中,其parent属性作用是指定其父类,并继承父类的注入属性。不仅如此,子类还可以修改或者覆盖父类的属性值。例如上述代码中的子类修改父类的baseDAO到属性:

<bean id="BaseService" class="com.watson.BaseService" />
 <property name="baseDAO" ref="baseDAO" />
</bean>
<bean id="serviceA" class="com.watson.ServiceA" parent="baseService" />
<property name="baseDAO" ref="baseDAO2" />
</bean>

而对于父类的List等集合属性,子类可以继承父类的值,并且在其基础上进行增加新的值:

<bean id="BaseService" class="com.watson.BaseService" />
 <property name="listValue">  
  <list>  
   <value>listValue1</value>  
   <value>listValue2</value>  
  </list>  
 </property> 
</bean>
<bean id="serviceA" class="com.watson.ServiceA" parent="baseService" />
 <property name="listValue">  
  <list>  
   <value>listValue3</value>  
   <value>listValue4</value>  
  </list>  
 </property> 
</bean>

Annotation方式提取父类

上面的方法是在XML配置文件中进行的配置。而对现在Spring3流行的Annotation方式,其实更加的方便,完整示例如下:

BaseDAO代码:

@Component
public class BaseDAO {
 public String service() {
  return "Success!";
 }
}

Services代码:

//所有业务类的父类
public class BaseService {
 @Autowired
 protected BaseDAO baseDAO;
}
 
//第一个业务类
@Component
public class ServiceA extends BaseService  {
 public String service() {
  return baseDAO.service();
 }
}
//第二个业务类
@Component
public class ServiceB extends BaseService  {
 public String service() {
  return baseDAO.service();
 }
}

Action层代码:

@Controller
@RequestMapping(value = "/testaction")
public class TestAction {
 @Autowired
 private ServiceA service;
 
 @RequestMapping(value = "/")
 public @ResponseBody String home(Model model) {
  return service.service();
 }
}

这里根本就不需要进行parent属性子类的配置,可以完美的提取父类,并且可以顺利的使用父类的公用属性。至于原理,没有去看源码的处理方式,估计和上述XML配置是异曲同工的,只是在这里增加了对父类的检测。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • java线程池:获取运行线程数并控制线程启动速度的方法

    java线程池:获取运行线程数并控制线程启动速度的方法

    下面小编就为大家带来一篇java线程池:获取运行线程数并控制线程启动速度的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • 详解Spring依赖注入的三种方式使用及优缺点

    详解Spring依赖注入的三种方式使用及优缺点

    这篇文章主要介绍了spring依赖注入的三种方式的使用方法,以及优缺点的介绍,通过代码示例介绍的非常详细,感兴趣的小伙伴可以参考一下
    2023-04-04
  • SpringBoot 在测试时如何指定包的扫描范围

    SpringBoot 在测试时如何指定包的扫描范围

    这篇文章主要介绍了SpringBoot 在测试时如何指定包的扫描范围,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • IDEA之如何关闭/开启引用提示Usages

    IDEA之如何关闭/开启引用提示Usages

    这篇文章主要介绍了IDEA之如何关闭/开启引用提示Usages问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • 三行Java代码实现计算多边形的几何中心点

    三行Java代码实现计算多边形的几何中心点

    因为工作需要计算采煤机工作面的中心点,如果套用数学的计算公式,用java去实现,太麻烦了。本文将利用java几何计算的工具包,几行代码就能求出多变形的中心,简直yyds!还不快跟随小编一起学起来
    2022-10-10
  • 详解springboot 使用c3p0数据库连接池的方法

    详解springboot 使用c3p0数据库连接池的方法

    本篇文章主要介绍了springboot 使用c3p0数据库连接池的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-09-09
  • java获取文件大小的几种方法

    java获取文件大小的几种方法

    这篇文章主要介绍了java获取文件大小的几种方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-10-10
  • Java求出任意数字的各个位数之和方式

    Java求出任意数字的各个位数之和方式

    这篇文章主要介绍了Java求出任意数字的各个位数之和方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01
  • SpringCloud基于RestTemplate微服务项目案例解析

    SpringCloud基于RestTemplate微服务项目案例解析

    这篇文章主要介绍了SpringCloud基于RestTemplate微服务项目案例,在写SpringCloud搭建微服务之前,先搭建一个不通过springcloud只通过SpringBoot和Mybatis进行模块之间通讯,通过一个案例给大家详细说明,需要的朋友可以参考下
    2022-05-05
  • Knife4j 3.0.3 整合SpringBoot 2.6.4的详细过程

    Knife4j 3.0.3 整合SpringBoot 2.6.4的详细过程

    本文要讲的是 Knife4j 3.0.3 整合SpringBoot 2.6.4,在SpringBoot 2.4以上的版本和之前的版本还是不一样的,这个也容易导致一些问题,本文就这两个版本的整合做一个实战介绍
    2022-09-09

最新评论