背景

  简单工厂模式定义起来比较容易,但是在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对象就可以正常使用了。