案例
获取1个方法的运行时间
使用继承实现(继承)
使用实现接口实现(组合)
//继承
public class Tank {
public void move() {
System.out.println("Tank is moving ~~~");
}
}
//继承基类重写里面的方法对其进行扩展(对Tank类的move()方法加上获取运行时间的代码)
public class TimeHandlerTank extends Tank {
@Override
public void move() {
long start = System.currentTimeMillis();
super.move();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("move时间: " + String.valueOf(end - start));
}
}
public static void main(String[] args) {
new TimeHandlerTank().move();
}
//结果
Tank is moveing~~~
move时间: 1003
//组合
public interface Moveable {
void move();
}
public class Tank implements Moveable {
public void move() {
System.out.println("Tank is moveing~~~");
}
}
//通过构造方法传入Tank
public class TimeHandler implements Moveable{
private Moveable moveable ;
public TimeHandler(Moveable moveable) {
this.moveable = moveable;
}
//实现move()方法的时候,调用Tank的move()方法,同时加上获取运行时间的代码
public void move() {
long start = System.currentTimeMillis();
moveable.move();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("move时间: " + String.valueOf(end - start));
}
}
public static void main(String[] args) {
Moveable tank = new Tank();
new TimeHandler(tank).move();
}
获取一个方法的执行时间同时记录日志
使用继承的方式就是继续继承重写方法,这样的话就会出现好多类(类爆炸),如果使用实现接口的方式(组合)将会避免这个问题。
//组合实现,对于上面组合的代码添加LogHandler类
public class LogHandler implements Moveable{
private Moveable moveable;
public LogHandler(Moveable moveable) {
this.moveable = moveable;
}
public void move() {
moveable.move();
System.out.println("记录日志~~~~");
}
}
//main方法修改如下:
public static void main(String[] args) {
Moveable tank = new Tank();
new LogHandler(new TimeHandler(tank)).move();
}
结果:
Tank is moveing~~~
move时间: 1005
记录日志~~~~
jdk动态代理
虽然可以通过编写hanler来扩展类,但是这样的话会产生的大量的类,如何能达到这样的效果又不产生大量的类呢 ,其实通过反射+动态编译便可以解决。其实jdk就是这样实现的,下面是jdk动态代理的例子:
//定义接口
public interface ForumService {
void removeTopic(int topicId);
void removeForum(int forumId);
}
//实现接口
public class ForumServiceImpl implements ForumService {
public void removeTopic(int topicId) {
System.out.println("模拟删除topic记录:" + topicId);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void removeForum(int forumId) {
System.out.println("模拟删除formId:" + forumId);
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//运行时间代码(横切代码)
public class PerformanceMonitor {
public static void begin(String method){
System.out.println("begin monitor...");
}
public static void end(){
System.out.println("end monitor");
}
}
//将目标业务类和横切代码编制在一起
public class PerformanceHandler implements InvocationHandler {
private Object target;
public PerformanceHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
PerformanceMonitor.begin(target.getClass().getName() + "." + method.getName());
Object obj = method.invoke(target, args);
PerformanceMonitor.end();
return obj;
}
}
//
public class TestForumService {
public static void main(String[] args) {
//希望被代理的目标类
ForumService target = new ForumServiceImpl();
//将目标业务类和横切代码编制在一起
PerformanceHandler handler = new PerformanceHandler(target);
//返回代理对象
ForumService proxy = (ForumService) Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), handler);
proxy.removeForum(10);
System.out.println("*****************");
proxy.removeTopic(120);
}
}
//结果:
begin monitor...
模拟删除formId:10
end monitor
*****************
begin monitor...
模拟删除topic记录:120
end monitor
模拟实现jdk动态代理
//定义被代理对象的类必须实现的接口
public interface Moveable {
void move();
}
//被代理对象实现接口
public class Tank implements Moveable {
public void move() {
System.out.println("Tank Moving...");
try {
Thread.sleep(new Random().nextInt(10000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//反射调用被代理对象接口
public interface InvocationHandler {
public void invoke(Object o, Method m);
}
//实现反射调用被代理对象接口
public class TimeHandler implements InvocationHandler {
private Object target;
public TimeHandler(Object target) {
super();
this.target = target;
}
public void invoke(Object o, Method m) {
long start = System.currentTimeMillis();
System.out.println("starttime:" + start);
System.out.println(o.getClass().getName());
try {
m.invoke(target);
} catch (Exception e) {
e.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("time:" + (end - start));
}
}
//产生代理对象
public class Proxy {
public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception { //JDK6 Complier API, CGLib, ASM
String methodStr = "";
String rt = "\r\n";
Method[] methods = infce.getMethods();
/*
for(Method m : methods) {
methodStr += "@Override" + rt +
"public void " + m.getName() + "() {" + rt +
" long start = System.currentTimeMillis();" + rt +
" System.out.println(\"starttime:\" + start);" + rt +
" t." + m.getName() + "();" + rt +
" long end = System.currentTimeMillis();" + rt +
" System.out.println(\"time:\" + (end-start));" + rt +
"}";
}
*/
for(Method m : methods) {
methodStr += rt +
"public void " + m.getName() + "() {" + rt +
" try {" + rt +
" Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
" h.invoke(this, md);" + rt +
" }catch(Exception e) {e.printStackTrace();}" + rt +
"}";
}
String src =
"package com.bjsxt.proxy;" + rt +
"import java.lang.reflect.Method;" + rt +
"public class $Proxy1 implements " + infce.getName() + "{" + rt +
" public $Proxy1(InvocationHandler h) {" + rt +
" this.h = h;" + rt +
" }" + rt +
" com.bjsxt.proxy.InvocationHandler h;" + rt +
methodStr +
"}";
String fileName =
"/Users/wjk/myproject/test/design_pattern/src/main/java/com/bjsxt/proxy/$Proxy1.java";
File f = new File(fileName);
FileWriter fw = new FileWriter(f);
fw.write(src);
fw.flush();
fw.close();
//compile(Java动态编译)
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
Iterable units = fileMgr.getJavaFileObjects(fileName);
CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
t.call();
fileMgr.close();
//load into memory and create an instance
URL[] urls = new URL[] {new URL("file:/" + "/Users/wjk/myproject/test/design_pattern/src/main/java")};
URLClassLoader ul = new URLClassLoader(urls);
Class c = ul.loadClass("com.bjsxt.proxy.$Proxy1");
System.out.println(c);
Constructor ctr = c.getConstructor(InvocationHandler.class);
Object m = ctr.newInstance(h);
//m.move();
return m;
}
}
public class Client {
public static void main(String[] args) throws Exception {
Tank t = new Tank();
InvocationHandler h = new TimeHandler(t);
Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class, h);
m.move();
}
}
//结果
class com.bjsxt.proxy.$Proxy1
starttime:1452505387375
com.bjsxt.proxy.$Proxy1
Tank Moving...
time:9798
参考资料:
《Spring3.x企业应用开发实践》
《马士兵——设计模式》