实例分析Java的代理机制

(0)准备工作

本文使用log4j日志工具实现日志输出,添加log4j的步骤如下:

(1)下载地址:http://logging.apache.org/log4j/1.2/download.html,下载 【log4j-1.2.17.zip

(2)将 【log4j-1.2.17.jar】 文件,复制到 lib 下

(3)然后右击添加到资源文件。


(一)通用的日志输出方法

通用的日志输出方法即是在每个业务逻辑方法中,都编写记录日志的代码

  • (1)在每个业务逻辑方法中添加日志记录代码
  • (2)测试功能
//****************TimeBook.java*******************
//在业务逻辑中使用log4j作为日志输出的工具
import org.apache.log4j.Level;	
import org.apache.log4j.Logger;

public class TimeBook {
	private Logger logger = Logger.getLogger(this.getClass().getName());

	//doAuditing()方法用来处理实际业务中的考勤审核
	//参数name,用来传入是谁执行了类TimeBook中的doAuditing()方法
	public void doAuditing(String name) {
		logger.log(Level.INFO, name + " 开始审核数据...");
		// 审核数据的相关程序
		logger.log(Level.INFO, name + " 审核数据结束...");
	}
}
//****************TestHelloWorld.java******************
import com.gc.action.TimeBook;

public class TestHelloWorld {
	public static void main(String[] args){
		TimeBook timeBook = new TimeBook();
		timeBook.doAuditing("张三");
	}
}

结果
[ INFO ] 2020-04-19 21:42:44 [main] com.gc.action.TimeBook  - 张三 开始审核数据...
[ INFO ] 2020-04-19 21:42:44 [main] com.gc.action.TimeBook  - 张三 审核数据结束...

使用这种方法,假如程序中其他的代码都需要日志输出功能,则都需要添加上述代码,造成很大耦合。我们可以通过面向接口编程来解决这个问题。


(二)面向接口编程的日志输出方法

  • (1)将doAuditing()方法提取出来成为接口 TimeBookInterface
  • (2)通过TimeBook实现该接口,并编写具体的审核业务逻辑
  • (3)设置一个代理类进行日志输出
  • (4)测试
//*****************TimeBookInterface.java*******************
public interface TimeBookInterface {
	public void doAuditing(String name);
}
//****************TimeBookInterface.java**********************
public class TimeBook implements TimeBookInterface{
	//doAuditing()方法用来处理实际业务中的考勤审核
	//参数name,用来传入是谁执行了类TimeBook中的doAuditing()方法
	public void doAuditing(String name) {
		// 审核数据的相关程序
	}
}
//****************TimeBookProxy.java********************
//代理程序
public class TimeBookProxy {
	private Logger logger = Logger.getLogger(this.getClass().getName());
	private TimeBookInterface timeBookInterface;       //定义一个接口对象

	public TimeBookProxy(TimeBookInterface timeBookInterface) {
		this.timeBookInterface = timeBookInterface;    //使接口指向子对象
	}
	//实际业务处理
	public void doAuditing(String name) {
		logger.log(Level.INFO, name + " 开始审核数据...");
		timeBookInterface.doAuditing(name);            //调用子对象的方法
		logger.log(Level.INFO, name + " 审核数据结束...");
	}
}
//**************TestHelloWorld.java******************
public class TestHelloWorld {
	public static void main(String[] args){
		TimeBookProxy timeBookProxy = new TimeBookProxy(new TimeBook());
		timeBookProxy.doAuditing("张三");
	}
}

结果
[ INFO ] 2020-04-19 23:31:47 [main] com.gc.action.TimeBookProxy  - 张三 开始审核数据...
[ INFO ] 2020-04-19 23:31:47 [main] com.gc.action.TimeBookProxy  - 张三 审核数据结束...

该方法使用代理类实现日志的输出,实现了日志代码的重用性。但是仍具有局限性,因为要使用代理类就必须实现固定的接口。而 Java代理机制具有通用性,不管是不是实现这个接口,都可以实现日志的输出。


(三)使用Java代理机制的日志输出方法

  • (1)编写一个接口TimeBookInterface
  • (2)用TimeBook实现TimeBookInterface接口,并实现具体审核代码
  • (3)编写一个代理类LogProxy实现 InvocationHandler
  • (4)测试
//*****************TimeBookInterface.java*******************
public interface TimeBookInterface {
	public void doAuditing(String name);
}
//****************TimeBookInterface.java**********************
public class TimeBook implements TimeBookInterface{
	//doAuditing()方法用来处理实际业务中的考勤审核
	//参数name,用来传入是谁执行了类TimeBook中的doAuditing()方法
	public void doAuditing(String name) {
		// 审核数据的相关程序
	}
}
//****************LogProxy.java**********************
public class LogProxy implements InvocationHandler {
	private Logger logger = Logger.getLogger(this.getClass().getName());
	private Object delegate;
	//绑定代理对象
	public Object bind(Object delegate) {
		this.delegate = delegate;
		return Proxy.newProxyInstance(delegate.getClass().getClassLoader(), delegate.getClass().getInterfaces(), this);
	}
	//针对接口编程
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object result = null;
		try {
			//在方法调用前后进行日志输出
			logger.log(Level.INFO, args[0] + " 开始审核数据...");
			result = method.invoke(delegate, args);                //程序通过该代理运行
			logger.log(Level.INFO, args[0] + " 审核数据结束...");
		} catch (Exception e) {
			logger.log(Level.INFO, e.toString());
		}
		return result;
	}
}
//***************TestHelloWorld.java********************
public class TestHelloWorld {
	public static void main(String[] args){
		LogProxy logProxy = new LogProxy();
		TimeBookInterface timeBookProxy = (TimeBookInterface)logProxy.bind(new TimeBook());
		timeBookProxy.doAuditing("张三");
	}
}

结果
[ INFO ] 2020-04-20 00:09:48 [main] com.gc.action.LogProxy  - 张三 开始审核数据...
张三
[ INFO ] 2020-04-20 00:09:48 [main] com.gc.action.LogProxy  - 张三 审核数据结束...

输出结果的第二行,张三是通过代理类 LogProxy.java 中的 result = method.invoke(delegate, args); 去调用 doAufiting() 函数。通过Java代理机制,真正的实现了业务逻辑和输出日志信息代码的分离。


总结

  • 通用的方式:需要在每个类里都增加对输出日志信息的代码。
  • 面向接口编程:实现了业务逻辑与输出日志信息代码的分类,但必须依赖固定的接口。
  • Java代理机制:真正实现了日志信息代码的重用,且不依赖于固定接口。

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肥羊汤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值