在前一篇博客中讲解了一些代理模式的基础知识,是否还记得它们的分类:静态代理和动态代理。那么它们到底怎么用呢?接下来就结合实战来体验一下动态代理的奥妙。
一、背景
在drp实现FlowCardManagerImpl的时候,刚开始每个方法的实现都有打开-提交-回滚-关闭事务的流程,但是Manager层的作用是实现业务逻辑,和事务的实现没有必然的联系,并且都是重复的代码。所以这里明显存在着问题,急需要将事务与Manager分离。那么怎么实现呢?答案就是用动态代理来实现。
二、准备
在Java中实现动态代理机制,必须做一些准备工作。即:需要java.lang.reflect.InvocationHandler接口和java.lang.reflect.Proxy 类的支持 。
java.lang.reflect.InvocationHandler接口的定义如下
public interface InvocationHandler {
public Object invoke(Object proxy,Method method, Object[] args) throws Throwable;
}
Object proxy:被代理的对象
Method method:要调用的方法
Object[] args:方法调用时所需要参数
java.lang.reflect.Proxy类的定义如下
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h) throwsIllegalArgumentException
CLassLoader loader:类的加载器
Class<?> interfaces:得到全部的接口
InvocationHandler h:得到InvocationHandler接口的子类的实例
三、实现
(一)采用动态代理封装事务
package com.bjpowernode.drp.util;
importjava.lang.reflect.InvocationHandler;
importjava.lang.reflect.InvocationTargetException;
importjava.lang.reflect.Method;
importjava.lang.reflect.Proxy;
importjava.sql.Connection;
/**
* 采用动态代理封装事务
* TransactionHandler实现InvocationHandler接口,覆写invoke()方法
* 代理事务的业务写在invoke()方法中
* @author yujie
*
*/
public classTransactionHandler implements InvocationHandler {
privateObject targetObject;
publicObject newProxyInstance(Object targetObject){
this.targetObject= targetObject;
//通过proxy直接创建动态代理类实例,
//targetObject.getClass().getClassLoader():类的加载器
//targetObject.getClass().getInterfaces():得到全部的接口
//this:得到InvocationHandler接口的子类的实例,即invoke
returnProxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(),this);
}
/**
* Object proxy:被代理的对象
*Method method:要调用的方法
*Object[] args:方法调用时所需要参数
*/
publicObject invoke(Object proxy, Method method, Object[] args)
throwsThrowable {
Connectionconn = null;
Objectret = null;
try{
//从ThreadLocal中取得Connection
conn= ConnectionManager.getConnection();
if(method.getName().startsWith("add")||
method.getName().startsWith("del")||
method.getName().startsWith("modigy")){
//手动控制事务提交
ConnectionManager.beginTransaction(conn);
}
//调用目标对象的业务逻辑方法
ret= method.invoke(targetObject, args);
if(!conn.getAutoCommit()){
//提交事务
ConnectionManager.commitTransaction(conn);
}
}catch(ApplicationExceptione){
//回滚事务
ConnectionManager.rollbackTransaction(conn);
throwe;
}catch(Exceptione) {
e.printStackTrace();
if(einstanceof InvocationTargetException){
InvocationTargetExceptionete = (InvocationTargetException)e;
throwete.getTargetException();
}
//回滚事务
ConnectionManager.rollbackTransaction(conn);
thrownew ApplicationException("操作失败!");
}finally{
ConnectionManager.closeConnection();
}
returnret;
}
}<span style="font-family: SimSun; font-size: 14pt; "> </span>
(二)Servlet的调用
privateFlowCardManager flowCardManager;
@Override
publicvoid init(ServletConfig config) throws ServletException {
flowCardManager =(FlowCardManager)getBeanFactory().getServiceObject(FlowCardManager.class);
TransactionHandler transactionHandler = newTransactionHandler();
flowCardManager =(FlowCardManager)transactionHandler.newProxyInstance(flowCardManager);
}
@Override
protectedvoid doGet(HttpServletRequest request, HttpServletResponse response)
throwsServletException, IOException {
if(Constants.SHOW_ADD.equals(getCommand())) {
showAdd(request,response);
}elseif (Constants.ADD.equals(getCommand())) {
add(request,response);
}elseif (Constants.DEL.equals(getCommand())) {
del(request,response);
}elseif (Constants.MODIFY.equals(getCommand())) {
}else{
search(request,response);
}
}
@Override
protectedvoid doPost(HttpServletRequest request, HttpServletResponse response)
throwsServletException, IOException {
doGet(request,response);
}
/**
* 添加
* @param request
* @param response
* @throws ServletException
* @throws IOException
*/
privatevoid add(HttpServletRequest request, HttpServletResponse response)
throwsServletException, IOException {
//供方分销商代码
StringclientId = request.getParameter("clientInnerId");
//需方客户代码
String[]aimIds = request.getParameterValues("aimInnerId");
//物料代码
String[]itemNos = request.getParameterValues("itemNo");
//操作数量
String[]qty = request.getParameterValues("qty");
FlowCardflowCard = new FlowCard();
//操作类型,
flowCard.setOpttype("A");
//取得会计核算期,正常情况下应该从session中取得
FiscalYearPeriodfiscalYearPeriod = new FiscalYearPeriod();
fiscalYearPeriod.setId(1);
flowCard.setFiscalYearPeriod(fiscalYearPeriod);
//分销商
Clientclient = new Client();
client.setId(Integer.parseInt(clientId));
flowCard.setClient(client);
//取得录入人
flowCard.setRecorder(getCurrentUser());
//操作日期
flowCard.setOptDate(newDate());
//单据状态
flowCard.setVouSts("N");
List<FlowCardDetail>flowCardDetailList = new ArrayList();
for(int i=0; i<aimIds.length; i++) {
FlowCardDetailflowCardDetail = new FlowCardDetail();
//需方客户
AimClientaimClient = new AimClient();
aimClient.setId(Integer.parseInt(aimIds[i]));
flowCardDetail.setAimClient(aimClient);
//物料
Itemitem = new Item();
item.setItemNo(itemNos[i]);
flowCardDetail.setItem(item);
//操作数量
flowCardDetail.setOptQty(newBigDecimal(qty[i]));
//调整标记
flowCardDetail.setAdjustFlag("N");
flowCardDetailList.add(flowCardDetail);
}
flowCard.setFlowCardDetailList(flowCardDetailList);
// //通过工厂取得业务逻辑对象
FlowCardManagerflowCardManager =(FlowCardManager)getBeanFactory().getServiceObject(FlowCardManager.class);
flowCardManager.addFlowCard(flowCard);
response.sendRedirect(request.getContextPath()+ "/servlet/flowcard/FlowCardServlet?command=" + Constants.QUERY);
}<span style="font-size: 14pt; font-family: Calibri; "> </span>
(三)Manager的修改
<span style="font-size: 14pt;">/**
* 流向单维护服务层实现
* @author yujie
*
*/
public classFlowCardManagerImpl implements FlowCardManager {
privateFlowCardDao flowCardDao;
publicFlowCardManagerImpl(){
this.flowCardDao= (FlowCardDao)BeanFactory.getInstance().getDaoObject(FlowCardDao.class);
}
@Override
publicvoid addFlowCard(FlowCard flowCard) throws ApplicationException {
try{
//生成流向单单号
StringflowCardVouNo = flowCardDao.generateVouNo();
//添加流向单主信息
flowCardDao.addFlowCardMaster(flowCardVouNo,flowCard);
//添加流向单明细信息
flowCardDao.addFlowCardDetail(flowCardVouNo,flowCard.getFlowCardDetailList());
}catch(DaoExceptione) {
thrownew ApplicationException("添加流向单失败!");
}
}
}
</span><h2><span style="font-size:18px;">(四)Manager修改之前</span></h2><span style="font-size: 14pt;">/**
* 流向单维护服务层实现
* @author yujie
*
*/
public classFlowCardManagerImpl implements FlowCardManager {
privateFlowCardDao flowCardDao;
publicFlowCardManagerImpl(){
this.flowCardDao= (FlowCardDao)BeanFactory.getInstance().getDaoObject(FlowCardDao.class);
}
@Override
publicvoid addFlowCard(FlowCard flowCard) throws ApplicationException {
Connectionconn=null;
try{
//取得connection
conn = ConnectionManager.getConnection();
//开启事务
ConnectionManager.beginTransaction(conn);
//生成流向单单号
StringflowCardVouNo = flowCardDao.generateVouNo();
//添加流向单主表信息
flowCardDao.addFlowCardMaster(flowCardVouNo,flowCard);
//添加流向单明细信息
flowCardDao.addFlowCardDetail(flowCardVouNo,flowCard.getFlowCardDetailList());
//提交事务
ConnectionManager.commitTransaction(conn);
}catch(DaoExceptione){
//回滚事务
ConnectionManager.rollbackTransaction(conn);
thrownew ApplicationException("添加流向单失败!");
}finally{
//关闭connection并从threadlocal中清楚
ConnectionManager.closeConnection();
}
}
}</span>
四、对比
无动态代理
用动态代理
通过以上用了代理和没用代理的比较可以发现动态代理的巨大优点,它可以大大减少代码量,将其公共的代码封装为动态代理类,在程序运行的过程中判断到底用哪个具体的被代理对象,从而达到解耦的效果。
五、总结
通过动态代理的利用,可以总结下动态代理的代理机制及特点:
1.通过实现 InvocationHandler 接口创建自己的调用处理器;
2.通过为 Proxy 类指定 ClassLoader对象和一组 interface来创建动态代理类;
3.通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;
4.通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。