一、场景
现在有一个需求,比如,现在有加减乘除四个方法,要求在执行这行方法的前后,分别做日志打印,要求打印出入参和运算结果。
二、基本实现 1、加减乘除接口public interface ArithmeticCalculator {
int add(int i,int j);
int sub(int i,int j);
int mul(int i, int j);
int div(int i, int j);
}
2、接口实现
public class ArithmeticCalculatorLoggingImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
System.out.println("the method add begins with [" + i +"," + j + "]");
int result = i + j;
System.out.println("the method ends with " +result);
return result;
}
@Override
public int sub(int i, int j) {
System.out.println("the method add begins with [" + i +"," + j + "]");
int result = i - j;
System.out.println("the method ends with " +result);
return result;
}
@Override
public int mul(int i, int j) {
System.out.println("the method add begins with [" + i +"," + j + "]");
int result = i * j;
System.out.println("the method ends with " +result);
return result;
}
@Override
public int div(int i, int j) {
System.out.println("the method add begins with [" + i +"," + j + "]");
int result = i / j;
System.out.println("the method ends with " +result);
return result;
}
}
3、测试方法
public class Main {
public static void main(String[] args) {
ArithmeticCalculator arithmeticCalculator = new ArithmeticCalculatorLoggingImpl();
arithmeticCalculator.add(2, 3);
}
}
4、输出结果:
从上面代码可以看出,日志的输出完全和运算方法耦合在一起,如果现在有需求改变,要求在方法执行前后,再加入执行时间,这样的话,就得一行一行的改代码,非常不利于维护。下面采用代理模式,来解决上述问题。
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
@Override
public int add(int i, int j) {
int result = i + j;
return result;
}
@Override
public int sub(int i, int j) {
int result = i - j;
return result;
}
@Override
public int mul(int i, int j) {
int result = i * j;
return result;
}
@Override
public int div(int i, int j) {
int result = i / j;
return result;
}
}
3、编写代理类
public class ArithmeticCalculatorLogginProxy {
//要代理的对象
private ArithmeticCalculator target;
public ArithmeticCalculatorLogginProxy(ArithmeticCalculator target) {
this.target = target;
}
public ArithmeticCalculator getLoggingProxy(){
ArithmeticCalculator proxy = null;
//代理对象由哪一个类加载器负责加载
ClassLoader loader = target.getClass().getClassLoader();
//代理对象的类型,即其中有哪些方法
Class[] interfaces = new Class[]{ArithmeticCalculator.class};
//当调用代理对象其中的方法时,执行该代码
InvocationHandler h = new InvocationHandler() {
/*
*proxy : 正在返回的代理对象,一般情况下,在invoke方法中都不使用该对象
*method : 正在被调用的方法
*args : 调用方法时,传入的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
System.out.println("the method " + methodName + "begins with " + Arrays.asList(args));
Object result = method.invoke(target, args);
System.out.println("the method" + methodName + "ends with " + result);
return result;
}
};
proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, h);
return proxy;
}
}
4、测试代码
public class Main {
public static void main(String[] args) {
ArithmeticCalculator target = new ArithmeticCalculatorImpl();
ArithmeticCalculator proxy = new ArithmeticCalculatorLogginProxy(target).getLoggingProxy();
int result = proxy.add(2, 3);
System.out.println("-->" + result);
result = proxy.mul(2, 4);
System.out.println("-->" + result);
}
}
5、输出结果:
1、使用代理模式,就可以将日志的输出抽离出来,实现了解耦,但此种方法会要求对代理模式有很好的认识,在实际项目中,也很难写出这样的代码。所以,会在下面使用Spring的AOP来实现日志输出。