实现原理
工厂的定义有三种方式 1)<factory method 2)<factory value 3)组件类中的@Factory(
Component.getInstance
所有组件的使用都是从Component.getInstance开始的,包括Name和factory
1) 首先从上下文中找组件
2) 如果找不到再通过工厂定义创建或组件定义newInstance
3) 将结果进行Unwrap处理,如果结果不是组件实例并且组件有Unwrap注释,就直接返回结果,否则报异常;如果结果是组件实例再进行Unwrap处理
Object result = Contexts.lookupInStatefulContexts(name);
if (result==null && create)
{
result = getInstanceFromFactory(name);
if (result==null)
{
if (component==null)
{
}
else if ( component.getScope().isContextActive() )
{
result = component.newInstance();
}
}
}
if (result!=null)
{
if (component!=null)
{
if ( !component.isInstance(result) )不是组件的实例,有Unwrap注释就直接返回,没有报异常
{
if ( component.hasUnwrapMethod() ) return result; ///best way???
throw new IllegalArgumentException( "….”);
}
result = component.unwrap(result);获取的是组件,再进行unwrap处理
}
}
getInstanceFromFactory(String name)
三种工厂定义都设置进Init中,配置优先与类中定义
Init init = Init.instance();
if (init==null) //for unit tests, yew!
{
return null;
}
else
{
Init.FactoryMethod factoryMethod = init.getFactory(name);
//组件方法工厂,执行组件的方法
Init.FactoryExpression methodBinding = init.getFactoryMethodExpression(name);
//配置方法工厂
Init.FactoryExpression valueBinding = init.getFactoryValueExpression(name);
//配置值工厂
if ( methodBinding!=null && getOutScope( methodBinding.getScope(), null ).isContextActive() ) //let the XML take precedence
{
Object result = methodBinding.getMethodBinding().invoke();
return handleFactoryMethodResult( name, null, result, methodBinding.getScope() );
}
else if ( valueBinding!=null && getOutScope( valueBinding.getScope(), null ).isContextActive() ) //let the XML take precedence
{
Object result = valueBinding.getValueBinding().getValue();
return handleFactoryMethodResult( name, null, result, valueBinding.getScope() );
}
else if ( factoryMethod!=null && getOutScope( factoryMethod.getScope(), factoryMethod.getComponent() ).isContextActive() )
{
Object factory = Component.getInstance( factoryMethod.getComponent().getName(), true );
if (factory==null)
{
return null;
}
else
{
Object result = factoryMethod.getComponent().callComponentMethod( factory, factoryMethod.getMethod() );
return handleFactoryMethodResult( name, factoryMethod.getComponent(), result, factoryMethod.getScope() );
}
}
else
{
return null;
}
}
handleFactoryMethodResult
result为工厂方法返回的值或值绑定的值,如果
handleFactoryMethodResult(String name, Component component, Object result, ScopeType scope)
{
Object value = Contexts.lookupInStatefulContexts(name); //see if a value was outjected by the factory method
if (value==null) //usually a factory method returning a value
{
ScopeType outScope = getOutScope(scope, component);
if ( outScope!=STATELESS )
{
outScope.getContext().set(name, result);
}
return result;
}
else //usually a factory method with a void return type
{
if (scope!=UNSPECIFIED)
{
throw new IllegalArgumentException("factory method with defined scope outjected a value: " + name);
}
return value;
在配置文件
1)<factory> 声明让你指定一个值或者方法来绑定一个表达式,当它第一次被引用时,将被执行用来初始化一个context变量的值。
<factory name="contact" method="#{contactManager.loadContact}" scope="CONVERSATION"/>
<factory name="user" value="#{actor}" scope="STATELESS"/>
<factory name="contact" value="#{contactManager.contact}" scope="STATELESS"/>
2)你也可以为Seam组件创建一个别名(第二个名字)
<factory name="user" value="#{actor}" scope="STATELESS"/>
<factory name="contact" value="#{contactManager.contact}" scope="STATELESS"/>
3)auto-create="true" 用在 <factory> 声明中尤其常见
<factory name="session" value="#{entityManager.delegate}" scope="STATELESS" auto-create="true"/>
在组件类中
有两种工厂方法。
第一种返回一个值,Seam会把它绑定到上下文里:
第二种方法返回 void,它自己把值绑定到上下文变量:
@Factory(scope=CONVERSATION)
public List<Customer> getCustomerList() {//没有指定工厂名字就按bean取方法名称
return ... ;
}
与类的属性配合使用
@DataModel List<Customer> customerList;
@Factory("customerList")
public void initCustomerList() {
customerList = ... ;
}
@Unwrap
一个组件只能有一个@Unwrap
两种情况下,当我们引用 customerList 上下文变量,而其值为null时,工厂方法被调用,然后对这个值生命周期的其他部分就无法操纵了。更加强大的模式是 manager component pattern(管理者组件模式)。 在这种情况下,有一个Seam组件绑定到上下文变量,它管理着上下文变量的值,对客户端不可见。
管理者组件可以是任何组件,它需要一个 @Unwrap 方法。 该方法返回对客户端可见的值,每次 上下文变量被引用的时候都会被调用。
@Name("customerList")
@Scope(CONVERSATION)
public class CustomerListManager
{
...</