[weld] 咱们工人有力量
wuhaixing
2010-04-19
让container创建对象实例会有局限性,毕竟不能像你自己写代码那么随心所欲。所以CDI提供了Producer方法的机制,这也是将非bean的对象集成到CDI环境中最简单的办法。
依照规范: 工人阶级的历史先进性体现在如下几个方面:
比如,工人(以下简称Producer)方法可以:
Producer方法给我们带来了运行时的多态性。前面已经见过了alternative bean带来的部署时多态性,但一旦部署完成,系统就固定下来了。可Producer方法不受这个限制: @SessionScoped public class Preferences implements Serializable { private PaymentStrategyType paymentStrategy; ... @Produces @Preferred public PaymentStrategy getPaymentStrategy() { switch (paymentStrategy) { case CREDIT_CARD: return new CreditCardPaymentStrategy(); case CHECK: return new CheckPaymentStrategy(); case PAYPAL: return new PayPalPaymentStrategy(); default: return null; } } } 来看看注入的时候: @Inject @Preferred PaymentStrategy paymentStrategy; 它和Producer方法的返回类型、qualifier 标记相同,根据CDI的注入解析规则,他会找到Producer方法,container会调用这个方法来创建注入点所要求的实例。 |
|
wuhaixing
2010-04-19
8.1 Producer方法的空间
Producer方法的scope默认是@Dependent,所以container每次都会调用这个方法来创建符合注入要求的bean。因此,每个用户session中可能都会有多个PaymentStrategy对象。 要改变这种行为,可以给方法打上@SessionScoped标记。 @Produces @Preferred @SessionScoped public PaymentStrategy getPaymentStrategy() { ... } 现在,当调用Producer方法的时候,返回的PaymentStrategy会被放进session context中,因为session中已经有了这个实例,所以相同的session中再有需要时container也不会再调用方法了。 注意 Producer方法的scope和他所在的bean的scope是两码事。Producer方法的scope是指他所创建的bean的scope,决定的是调用方法的频率,以及返回对象的生命周期。而声明了这个方法的bean的scope决定的是这个bean本身的生命周期。就是说公司老板过的日子和打工的你过的日子不一样。 |
|
wuhaixing
2010-04-19
工薪族的价格,贵族式的享受
上面的代码有个问题,你亲自用了new!直接由程序创建的对象和由container创建的对象不是一个种,因此不能享受dependency injection,也没有interceptor。 如果你还想让Producer的返回值享受这些服务,可以把bean的实例注入到producer 方法中(哦,抱歉,这个世界上本来就没有公平可言!): @Produces @Preferred @SessionScoped public PaymentStrategy getPaymentStrategy(CreditCardPaymentStrategy ccps,CheckPaymentStrategy cps,PayPalPaymentStrategy ppps) { switch (paymentStrategy) { case CREDIT_CARD: return ccps; case CHEQUE: return cps; case PAYPAL: return ppps; default: return null; } } 但这又会产生新的问题,如果CreditCardPaymentStrategy是request-scoped bean,那producer 方法就会把这个本来应该呆在request session中的对象放到session scope中。request结束的时候,这个对象死了,可session中的bean们还不知道,以为还能找他解决问题。最麻烦的是container发现不了这个问题,你得自己多加小心,谨慎对待从producer方法返回的bean实例。 这个问题是可以解决的,而且方法不止一个。改变 CreditCardPaymentStrategy 实现的scope,或者改变producer方法的scope。 如果你还不满意,可以用@New 标记。 |
|
wuhaixing
2010-04-19
告诉container你要的是@New bean
先看代码: @Produces @Preferred @SessionScoped public PaymentStrategy getPaymentStrategy(@New CreditCardPaymentStrategy ccps, @New CheckPaymentStrategy cps, @New PayPalPaymentStrategy ppps) { switch (paymentStrategy) { case CREDIT_CARD: return ccps; case CHEQUE: return cps; case PAYPAL: return ppps; default: return null; } } 你说了,container就会给你创建一个新的CreditCardPaymentStrategy交给producer方法,这样producer方法返回的对象就会放进session context,也就会在session结束的时候才会被销毁。 |
|
wuhaixing
2010-04-19
管杀管埋
有时候你想亲手毁了producer方法产生的对象,总得有机会干干关闭jdbc连接之类的事吧。 @Produces @RequestScoped Connection connect(User user) { return createConnection(user.getId(), user.getPassword()); } 这时候可以在同一个类中定义一个与producer方法配对的disposer方法: void close(@Disposes Connection connection) { connection.close(); } disposer方法至少得有一个参数,标记为@Disposes,和producer方法返回类型及qualifiers一致。当context结束的时候,container会调用disposer方法,并且把producer方法返回的对象赋值给前面提到的那个参数。如果还有其他的参数,container会去找符合条件的bean进行赋值。 |
|
deeny
2010-04-19
站位有用吗?
|
|
qq905565585
2010-04-20
Produces @RequestScoped Connection connect(User user) {
2. return createConnection(user.getId(), user.getPassword()); 3.} |