一般情况,在每个调用的方法中直接添加日志信息,存在如下问题:
1.代码混乱:越来越多的非业务需求加入(如日志和验证等)后,原有的业务方法急剧膨胀,每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点;
2.代码分散:以日志需求为例,只是为了满足这个单一的需求,就不得不在多个模块里多次重复相同的日志代码,如果日志需求发生变化,必须修改所有的模块。
针对以上问题,使用动态代理带解决。
代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理取代原始对象。任何原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。
1.先定义一个接口
public interface Calc { int add(int i,int j); int sub(int i,int j); int multi(int i,int j); int div(int i,int j); }
2.定义一个接口的实现类,如
public class CalcImpl implements Calc{ public int add(int i, int j) { int result =i+j; return result; } public int sub(int i, int j) { int result =i-j; return result; } public int multi(int i, int j) { int result =i*j; return result; } public int div(int i, int j) { int result =i/j; return result; } }
3.定义代理类
public class CalcLoggingProxy { //要代理的对象 private Calc target; public CalcLoggingProxy(Calc target) { this.target=target; } public Calc getLoggingProxy(){ Calc proxy=null; //代理对象由哪一个类加载器加载 ClassLoader loader=target.getClass().getClassLoader(); //代理对象的类型,即其中有哪些方法 Class[] interfaces = new Class[]{Calc.class}; //当调用代理对象其中的方法试,就执行该方法 InvocationHandler h=new InvocationHandler() { /** * proxy:正在返回的代理对象,一般情况下很少使用 * method:正在调用的方法 * args:调用方法时,传入的参数 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("the method "+method.getName() +" begin with"+ Arrays.asList(args)); //执行target的方法,即执行代理对象的方法 Object result=method.invoke(target, args); System.out.println("the method "+method.getName() +" end with "+result); return result; } }; proxy=(Calc) Proxy.newProxyInstance(loader, interfaces, h); return proxy; } }
4.写个main方法测试效果
public static void main(String[] args) { Calc target =new CalcImpl(); Calc proxy =new CalcLoggingProxy(target).getLoggingProxy(); int result=proxy.add(1, 2); System.out.println("--->"+result); }
结果如下:
the method add begin with[1, 2]
the method add end with 3
--->3
用动态代理可以解决问题,但是用过spring的同学,肯定非常清楚spring中的AOP能轻松的解决此问题。