傳統模式下,每個 Session Bean 需對應一個 Delegate 類,手工封裝所有 public 方法,不僅工作量大,且若後續從 EJB 遷移至 JDO/Hibernate 等持久層,所有 Delegate 皆需修改,維護成本極高。
設計抽象基類 FacadeDelegate 統一處理 Home 查找與代理調用,具體 Delegate 僅需聲明介面,運行期透過反射動態路由至目標 Bean。
public abstract class FacadeDelegate {
private static String type = Resource.RemoteType;
public EJBHome getHome(String jndiName, Class homeClass) {
ServerLocatorAdapter adapter = ServerLocatorAdapter.getInstance();
return (EJBHome) adapter.getHome(type, jndiName, homeClass);
}
}
public class ServerLocatorAdapter {
private Map cache = Collections.synchronizedMap(new HashMap());
private static ServerLocatorAdapter me;
public Object getHome(String type, String jndiName, Class homeClass) throws Exception {
if (cache.containsKey(jndiName)) return cache.get(jndiName);
Object home = Resource.LocalType.equals(type)
? getLocalHome(jndiName, homeClass)
: getRemoteHome(jndiName, homeClass);
cache.put(jndiName, home);
return home;
}
// 利用反射動態實例化 LocalServerLocator / RemoteServerLocator
private Object getLocalHome(...) { ... Class.forName(Resource.LocalClass) ... }
private Object getRemoteHome(...) { ... Class.forName(Resource.RemoteClass) ... }
}
所有類名、方法名、JNDI 前綴集中在 Resource 屬性文件,實現「零代碼修改」切換部署模式。
Delegate.method(args)。EJBObject(create/findByPrimaryKey)。ServerLocator 實現與配置,無需修改業務 Delegate。public class LocalServerLocator {
private Context ic; private Map cache;
public EJBLocalHome getLocalHome(String jndi, Class clazz) {
if (cache.containsKey(jndi)) return (EJBLocalHome) cache.get(jndi);
Object ref = ic.lookup(jndi);
EJBLocalHome home = (EJBLocalHome) ref;
cache.put(jndi, home);
return home;
}
}