1.最原始的代码
package com.tansen.shop.test.proxy;
public interface Dao {
void insert();
void update();
void delete();
}
package com.tansen.shop.test.proxy;
public class DaoImpl implements Dao {
@Override
public void insert() {
System.out.println("DaoImpl.insert()");
}
@Override
public void update() {
System.out.println("DaoImpl.update()");
}
@Override
public void delete() {
System.out.println("DaoImpl.delete()");
}
}
2.我现在要给insert和update加上执行时间的日志
没有动态代理会怎么样?
package com.tansen.shop.test.proxy;
public class LogDao implements Dao{
Dao dao = new DaoImpl();
@Override
public void insert() {
System.out.println("insert执行开始时间"+System.currentTimeMillis());
dao.insert();
System.out.println("insert执行结束时间"+System.currentTimeMillis());
}
@Override
public void update() {
System.out.println("--------------------------------------------");
dao.update();
}
@Override
public void delete() {
System.out.println("--------------------------------------------");
System.out.println("insert执行开始时间"+System.currentTimeMillis());
dao.delete();
System.out.println("insert执行结束时间"+System.currentTimeMillis());
}
}
缺点:
方法调用前后输出时间的逻辑无法复用,如果有别的地方要增加这段逻辑就得再写一遍
如果Dao有其它实现类,那么必须新增一个类去包装该实现类,这将导致类数量不断膨胀
使用代理模式
package com.tansen.shop.test.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ProxyDao implements InvocationHandler {
private Object obj;
public ProxyDao(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if ("insert".equals(methodName) || "update".equals(methodName)) {
System.out.println(methodName + "()方法开始时间:" + System.currentTimeMillis());
Object result = method.invoke(obj, args);
System.out.println(methodName + "()方法结束时间:" + System.currentTimeMillis());
return result;
}
return method.invoke(obj, args);
}
}
调用
package com.tansen.shop.test.proxy;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
Dao dao = new DaoImpl();
Dao proxyDao = (Dao) Proxy.newProxyInstance(ProxyDao.class.getClassLoader(),new Class<?>[] {Dao.class},new ProxyDao(dao));
proxyDao.insert();
System.out.println("==========分割线===========");
proxyDao.delete();
System.out.println("==========分割线===========");
proxyDao.update();
}
}
结果
insert()方法开始时间:1513246731570
DaoImpl.insert()
insert()方法结束时间:1513246731571
==========分割线===========
DaoImpl.delete()
==========分割线===========
update()方法开始时间:1513246731571
DaoImpl.update()
update()方法结束时间:1513246731571
优点:
1.输出日志的逻辑被复用起来,如果要针对其他接口用上输出日志的逻辑,只要在newProxyInstance的时候的第二个参数增加Class<?>数组中的内容即可。
缺点
这种方式的缺点为:
1.JDK提供的动态代理只能针对接口做代理,不能针对类做代理
2.代码依然有耦合,如果要对delete方法调用前后打印时间,得在LogInvocationHandler中增加delete方法的判断