要求
-
执行加减乘除运算
-
日志:在程序执行期间追踪正在发生的活动
-
验证:希望计算器只能处理正数的运算
public class ArithmeticCalculatorImpl implements ArithmeticCalculator{ @Override public void add(int a, int b) { System.out.println("日志:The Method add begin ["+a+","+b+"]"); int result = a+b; System.out.println("result = " + result); } }
问题
-
代码混乱:越来越多的非业务需求(日志和验证等)加入后,原有的业务方法急剧膨胀。每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点。
-
代码分散: 以日志需求为例,只是为了满足这个单一需求,就不得不在多个模块(方法)里多次重复相同的日志代码。如果日志需求发生变化,必须修改所有模块。
//生成代理对象 public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
newProxyInstance方法中的三个参数
-
loader:类加载器对象,动态加载代理类
-
interfaces:目标类实现的所有接口,查看目标对象的方法都来自哪。
-
InvocationHandler接口类的对象
动态代理整个过程是在newProxyInstance
方法中的参数InvocationHandler中完成的,动态代理要做的业务逻辑放在InvocationHandler 的invoke方法中编写。
public Object invoke(Object proxy, Method method, Object[] args)
invoke方法中的三个参数
-
proxy:代理对象,调用代理方法会回过头调用invoke方法。
-
method:正在被调用的方法对象
-
args:正在被调用的方法参数
代理对象调用代理方法会回过头调用invoke方法。
- 业务类
@Service public class ArithmeticCalculatorImpl implements ArithmeticCalculator { @Override public int add(int n, int m) { return n+m; } }
- 自定义代理类
public class CalculProxy { //第一步:目标对象 private Object target; public CalculProxy(Object target) { this.target = target; } //第二步:获取代理对象 public Object getObject(Object obj){ return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() { //第三步:代理对象要做什么 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String name = method.getName(); System.out.println("日志:The Method "+name+" begin "+ Arrays.toString(args)); ////相当于执行目标类中的方法(add sub 方法) Object result = method.invoke(target, args); System.out.println(name+":result = " + result); return result; } }); } }
- 测试
@Test public void test_method07() { //第一步:获取目标对象 ArithmeticCalculatorImpl calculService = new ArithmeticCalculatorImpl(); //第二步:获取代理对象 CalculProxy calculProxy = new CalculProxy(calculService); ArithmeticCalculator proxy =(ArithmeticCalculator)calculProxy.getObject(calculService); proxy.add(1,2); }