背景
简单工厂模式定义起来比较容易,但是在Spring项目中,通过new创建出来的对象中,无法使用@Resource或@Autowired 注解实例化service层注入。
这个也比较容易理解,因为Spring的注入是在项目启动的时候执行的,所以后期new出来的实例对象中的注入注解就不会生效了。
举个例子:
假设有一个订单支付功能,我们有两种支付方式,一种支付宝支付,一种微信支付。用户在客户端进行支付的时候,需要从这两种支付方式中选取一种,来进行支付操作。
工厂类:
/**
* 工厂类,用来创造具体支付业务对象
*/
public class PayFactory {
private PayFactory() {} // 防止客户端无谓的创建工厂实例,将构造方法私有化
/**
* 具体的创造支付业务对象实例的方法
* @param type 从外部传入的选择条件
* @return
*/
public static Pay createPay(String type){
//应该根据某些条件去选择究竟创建哪一个具体的实现对象
//这些条件可以从外部传入,也可以从其它途径获取
//如果只有一个实现,可以省略条件,因为没有选择的必要
Pay pay = null;
if("ZFB".equals(type)){
pay = new ZhiFuBaoPay();
}else if("WX".equals(type)){
pay = new WeiXinPay();
}else{
System.out.println("支付方式不正确");
}
return pay;
}
}
微信支付业务类:
/**
* 微信支付
*/
public class WeiXinPay implements Pay {
@Autowired
private OrderService orderService;
@Override
public void pay(String orderNo) {
// 查询订单信息
// 这里会报java.lang.NullPointerException,orderService为null
Order order = orderService.selectByOrderNo(orderNo);
......
......
......
}
}
如果我们通过上边这种方式得到一个WeiXinPay的实例对象,那么在执行到
Order order = orderService.selectByOrderNo(orderNo);
这句时就会报错:java.lang.NullPointerException,这种情况发生的原因就是在
@Autowired
private OrderService orderService;
这里通过@Autowired注入时,注入失败。
解决办法
支付接口:
/**
* 支付接口
*/
public interface Pay {
/**
* 支付操作方法
*/
void pay();
}
具体支付业务类:
/**
* 微信支付
*/
@Component("WX")
public class WeiXinPay implements Pay{
@Autowired
private OrderService orderService;
public void pay() {
// 查询订单信息
Order order = orderService.selectByOrderNo(orderNo);
.......
.......
.......
}
}
/**
* 支付宝支付
*/
@Component("ZFB")
public class ZhiFuBaoPay implements Pay{
@Autowired
private OrderService orderService;
public void pay() {
// 查询订单信息
Order order = orderService.selectByOrderNo(orderNo);
.......
.......
.......
}
}
工厂类:
/**
* 工厂类,用来创造具体支付业务对象
*/
@Component
public class PayFactory {
/**
* 项目启动后,Spring会为实现了Pay接口并添加注解的类穿件对象实例,并放到此map中
*/
@Autowired
private Map<String , Pay> payMap;
public Pay createPay(String type){
return payMap.get(type);
}
}
在客户端用的时候,就可以这样用:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath:spring/spring-config-test.xml" })
public class TestPay {
@Autowired
private PayFactory payFactory;
@Test
public void testPay() {
Pay pay = payFactory.createPay("WX");
pay.pay();
}
}
这样,具体业务类中通过注解实例化的Service对象就可以正常使用了。