“虚包”模式定义了一个更高级别的类,它对进行调用的客户端与模型实体和 Java 持久性 API 操作之间的交互进行了封装和集中管理。为一系列实体操作提供了一个简单的接口。使用此虚包的客户端不必了解每个实体的 API 全部细节,也不必了解在访问实体管理器或其他事务管理器时使用的任何持久性机制。通过在进行调用的客户端和模型层中的实体之间引入虚包,可使代码与模型的耦合更松散,因而更易于维护。
正如代码示例 1 所示,使用虚包的代码更加简单明了。不使用虚包时,实体客户端需要了解实体的细节,每次需要访问实体时,您可能需要在其他地方剪切并粘贴类似的代码。引入虚包后,代码将隐藏模型层中实体的很多细节。
之前的代码 | 引入虚包后的代码 |
public class MyWebClient ... {
//now access entities in model
tier
EntityManager em = |
...
MyModelFacade();
myfacade.addItem(item); |
public class CatalogFacade implements ServletContextListener {
@PersistenceUnit(unitName="CatalogPu") private EntityManagerFactory emf;
@Resource UserTransaction utx;
public CatalogFacade(){}
public void contextDestroyed(ServletContextEvent sce) {
if (emf.isOpen()) {
emf.close();
}
}
public void contextInitialized(ServletContextEvent sce) {
ServletContext context = sce.getServletContext();
context.setAttribute("CatalogFacade", this);
}
public void addItem(Item item) throws InvalidItemException {
EntityManager em = emf.createEntityManager();
if(item.getName().length() == 0)
throw new InvalidItemException("The item" + " name cannot be empty. Please specify a name for the item. ");
try {
utx.begin();
em.joinTransaction();
em.persist(item);
utx.commit();
} catch(Exception exe){
System.err.println("Error persisting item: "+exe);
try {
utx.rollback();
} catch (Exception e) {
throw new RuntimeException("Error persisting item: "+ e.getMessage(), e);
}
throw new RuntimeException("Error persisting item: "+ exe.getMessage(), exe);
} finally {
em.close();
}
}
public Item getItem(int itemID){
EntityManager em = emf.createEntityManager();
Item item = em.find(Item.class,itemID);
em.close();
return item;
}
public List
EntityManager em = emf.createEntityManager();
List
em.close();
return items;
}
ServletContextListener
接口。这样,它便可使用标注,这在访问 Java EE 平台的 Java 持久性实体和相关服务时非常有用。现在,让我们看一下,Web 组件(如 Servlet)是如何查找并使用此虚包的。例如,在 addItem
方法中,需要使用用于设定事务界限的 JTA API 来访问实体。另外,还需要使用实体管理器 API 在数据库中存储新条目。将此代码统一放在虚包类中,比在每次需要实体访问时到处在应用程序中剪切和粘贴类似代码要好得多。代码示例 3:使用模型虚包访问 Java 持久性实体的 Web 组件
public class CatalogServlet extends HttpServlet {
private ServletContext context;
private CatalogFacade cf;
public void init(ServletConfig config)throws ServletException {
context = config.getServletContext();
cf = (CatalogFacade)context.getAttribute("CatalogFacade");
initPathMapping();
}
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
...
try {
if (selectedURL.equals("additem.do")) {
//get values from request and set in a
//new Item to then add to database
String desc = request.getParameter("item_desc");
String name = request.getParameter("item_name");
...
Item item = new Item();
item.setName(name);
item.setDescription(desc);
...
cf.addItem(item); //now call facade
...
}
}
init
方法获取的,然后作为字段存储在 Servlet 中,以便由其他客户端请求使用和共享。在处理请求时,Servlet 可以使用虚包,而不用理会实体细节和访问实体所需的任何持久性工作。
@Stateless
public class CatalogFacadeBean implements CatalogFacade
{
@PersistenceContext(unitName="CatalogPu")
private EntityManager em;
public void addItem(Item item) throws InvalidItemException {
if(item.getName().length() == 0)
throw new InvalidItemException("The
item" +
" name cannot be empty.
Please specify a name for the item. ");
em.persist(item);
}
public Item getItem(int itemID) {
Item item = em.find(Item.class,itemID);
return item;
}
public List<Item> getAllItems() {
List<Item> items =
em.createQuery("SELECT OBJECT(i) FROM Item i").getResultList();
return items;
}
}
public
class CatalogServlet extends HttpServlet {
private Map nameSpace;
private ServletContext context;
@EJB(name="CatalogFacadeBean") private CatalogFacade
cf;
public void init(ServletConfig config) throws
ServletException {
context =
config.getServletContext();
initPathMapping();
}
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
...
try {
if (selectedURL.equals("additem.do")) {
//get values from request and place
them into new Item
String desc =
request.getParameter("item_desc");
String name =
request.getParameter("item_name");
...
Item item = new Item();
item.setName(name);
item.setDescription(desc);
...
//use facade to add new Item to
database
cf.addItem(item);
...
}
...
}
@EJB(name="CatalogFacadeBean")
)来查找和获取虚包。还要注意,虚包是作为字段进行存储的,以便供其他客户端请求共享和使用。使用虚包可隐藏模型层访问的细节。