反射机制剖析(三): 谈谈代理模式是如何体现反射的

引出问题(打印日志为例)

程序运行应该记录运行日志信息,以作记录和分析。

打印日志代码放在实现类UserManagerImp

UserManagerImpl.java

public class UserManagerImpl implements UserManager {
 
publicvoid addUser(String userId, String userName) {
System.out.println("start-->>addUser()userId-->>" + userId);
try{
System.out.println("UserManagerImpl.addUser()userId-->>" + userId);
 
System.out.println("success-->>addUser()");
}catch(Exceptione) {
e.printStackTrace();
System.out.println("error-->>addUser()");
thrownew RuntimeException();
}        
}
}


 

 

可以看出:

需求变时需要改,对已经测试好的代码开放修改

但代码重复,工作量大,修改时恐怖

 

引入代理


代理模式是对象的结构型模式,给某一个对象提供了一个代理对象,并由代理对象控制对原对象的引用。其实


代理模式是在访问的对象时引入一定程度的间接性,这种间接性可以附加多种用途——模式其实就是加入间接层。

它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。


 

静态

代理对象在编译阶段被创建

打印日志代码抽出,放在UserManagerProxy


UserManagerImplProxy.java

publicclass UserManagerImplProxy implements UserManager {
 
privateUserManager userManager;
 
publicUserManagerImplProxy(UserManager userManager) {
this.userManager= userManager;
}
 
publicvoid addUser(String userId, String userName) {
try{
System.out.println("start-->>addUser()userId-->>" + userId);
userManager.addUser(userId,userName);
System.out.println("success-->>addUser()");
}catch(Exceptione) {
e.printStackTrace();
System.out.println("error-->>addUser()");
}        
}
}


 

第一个问题倒是解决了——关闭修改了。

但第二个问题——代码重复,工作量大,修改时恐怖,却没有得到解决。

 

 

动态

运行时,运用反射机制动态创建而成

打印日志代码放在LogHandler中


LogHandler.java

/**
 * 采用动态代理封装日志
 * @author TCH
 *
 */
publicclass LogHandler implements InvocationHandler {
 
privateObject targetObject;
 
publicObject newProxyInstance(Object targetObject) {
this.targetObject= targetObject;
returnProxy.newProxyInstance(targetObject.getClass().getClassLoader(),
   targetObject.getClass().getInterfaces(),this);
}
 
publicObject invoke(Object proxy, Method method, Object[] args)
throwsThrowable {
System.out.println("start-->>"+ method.getName());
for(int i=0; i<args.length; i++) {
System.out.println(args[i]);
}
Objectret = null;
try{
//调用目标方法
ret= method.invoke(targetObject, args);
System.out.println("success-->>"+ method.getName());
 
}catch(Exceptione) {
e.printStackTrace();
System.out.println("error-->>"+ method.getName());
 
//分析异常
if(e instanceof InvocationTargetException) {
InvocationTargetExceptionete = (InvocationTargetException)e;
throwete.getTargetException();
}
 
thrownew ApplicationException("调用目标方法" + method.getName() +" 失败!");
}
returnret;
}
}


 

 

  • 打印日志的代码可以被提炼出来,因为提供了独立服务,跟添加删除、具体逻辑等操作没关系,但又是公共部分,所以才能提炼出LogHandler。
  • 打印日志的代码只维护一份,省事多了,而且出问题几率大大降低。
  • JDK动态代理只能对实现了接口的类进行代理,采用JDK动态代理必须实现InvocationHandler接口,采用Proxy类创建相应的代理类。
  • InvocationTargetException包装自定义异常

在invoke方法中捕获异常,捕获到的自定义异常被包装在InvocationTargetException中的target属性中。

 

 

应用:使用动态代理封装事务,并在BeanFactory中返回代理对象

相当于在工厂和Manager接口间又加了一层,工厂通过代理访问Manager接口,把公共的独立的事务部分放在代理中。所以,模式其实就是加入了一个间接层。

 

TransactionHandler.java

/**
 * 采用动态代理封装事务
 * @author Administrator
 *
 */
publicclass TransactionHandler implements InvocationHandler {
 
privateObject targetObject;
 
publicObject newProxyInstance(Object targetObject) {
this.targetObject= targetObject;
returnProxy.newProxyInstance(targetObject.getClass().getClassLoader(),
   targetObject.getClass().getInterfaces(),this);
}
 
 
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("modify")){
//手动控制事务提交
ConnectionManager.beginTransaction(conn);
}        
//调用目标对象的业务逻辑方法
ret= method.invoke(targetObject, args);
if(!conn.getAutoCommit()) {
//提交事务
ConnectionManager.commitTransaction(conn);
}
//                }catch(ApplicationExceptione) {
//                        if(!conn.getAutoCommit()) {
//                                //回滚事务
//                                ConnectionManager.rollbackTransaction(conn);
//                        }
//                        throwe;
}catch(Exceptione) {
e.printStackTrace();
if(e instanceof InvocationTargetException) {
InvocationTargetExceptionete = (InvocationTargetException)e;
throwete.getTargetException();
}
if(!conn.getAutoCommit()) {
//回滚事务
ConnectionManager.rollbackTransaction(conn);
}
throw new ApplicationException("操作失败!");
}finally{
ConnectionManager.closeConnection();
}
returnret;
}
 
}


 

BeanFactory.java

/**
 *  统一工厂创建和管理对象
 *   抽象工厂+单例+反射实现,主要创建两个系列的产品代理:
 *  1、Manager系列
 *  2、Dao系列产品
 * @author TCH
 *
 */
publicclass BeanFactory {
 
// 使用单例维护一个实例
privatestatic BeanFactory instance = new BeanFactory();
 
privatefinal String beansConfigFile = "beans-config.xml";
 
//保存Service相关对象
privateMap serviceMap = new HashMap();
 
//保存Dao相关对象
privateMap daoMap = new HashMap();
 
privateDocument doc;
 
// 构造器:读取xml
privateBeanFactory() {
try{
doc= newSAXReader().read(Thread.currentThread().getContextClassLoader().getResourceAsStream(beansConfigFile));
}catch (DocumentException e) {
e.printStackTrace();
thrownew RuntimeException();
}
}
 
// 使用单例维护一个实例
publicstatic BeanFactory getInstance() {
returninstance;
}
 
/**
 * 根据产品编号取得Service系列产品
 * @param beanId
 * @return
 */
publicsynchronized Object getServiceObject(Class c){
//如果存在相关对象实例,返回
if(serviceMap.containsKey(c.getName())) {
returnserviceMap.get(c.getName());
}
ElementbeanElt = (Element)doc.selectSingleNode("//service[@id=\"" +c.getName() + "\"]");
StringclassName = beanElt.attributeValue("class");
Objectservice = null;
try{
service= Class.forName(className).newInstance();
 
//采用动态代理包装Service
TransactionHandler transactionHandler = newTransactionHandler();
service = transactionHandler.newProxyInstance(service);
 
//将创建好多的对象放到Map中
serviceMap.put(c.getName(),service);
}catch (Exception e) {
thrownew RuntimeException();
}
returnservice;
}
 
/**
 * 根据产品编号取得Service系列产品
 * @param beanId
 * @return
 */
publicsynchronized Object getDaoObject(Class c){
//如果存在相关对象实例,返回
if(daoMap.containsKey(c.getName())) {
returndaoMap.get(c.getName());
}
ElementbeanElt = (Element)doc.selectSingleNode("//dao[@id=\"" +c.getName() + "\"]");
StringclassName = beanElt.attributeValue("class");
Objectdao = null;
try{
dao= Class.forName(className).newInstance();
 
//将创建好多的对象放到Map中
daoMap.put(c.getName(),dao);
}catch (Exception e) {
thrownew RuntimeException();
}
returndao;
}
}


  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值