invoke方法来统一管理代理类中的方法该如何执行,该方法有三个参数
/**
* @param proxy:表示代理对象
* @param method:表示要执行的方法
* @param args:表示要执行的方法的参数列表
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在调用目标对象执行功能之前,加入额外的操作(这里是附加日志功能)
System.out.println("[日志] "+method.getName()+" 方法开始了,参数是:" + Arrays.toString(args));
//固定写法:调用目标对象实现的核心逻辑(最重要的步骤)
Object result = method.invoke(target, args);
//在调用目标对象执行功能之后,加入额外的操作(这里是附加日志功能)
System.out.println("[日志] "+method.getName()+" 方法结束了,结果是:" + result);
//固定写法:保证代理对象和目标对象的返回值一致
return result;
}
};
//返回(java.lang.reflect包下的)Proxy类的newProxyInstance方法所生产的代理对象
/**
* newProxyInstance方法有三个参数:
*
* 1、ClassLoader classLoader:指定加载(动态生成的)代理类的类加载器
* 类只有被加载后才能使用,(动态生成的)代理类需要用应用类加载器来加载
* 类加载器有四种:
* 跟类加载器(用于加载核心类库)
* 扩展类加载器(用于加载扩展类库)
* 应用类加载器(用于加载自己写的类或第三方jar包中的类)
* 自定义类加载器
*
* 2、Class<?>[] interfaces:指定代理对象要实现的接口
* 这个参数用于保证代理对象和目标对象有相同的方法列表
*
* 3、InvocationHandler invocationHandle:指定调用处理器
* 该处理器设置了代理对象实现的接口的方法被调用时,该如何执行
*/
return Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);
}
}
9.6.2、测试
@Test
public void testDynamicProxy(){
//根据目标对象来创建(动态)代理对象的工厂
ProxyFactory proxyFactory = new ProxyFactory(new CalculatorImpl());
//通过(动态)代理对象的工厂,生成目标对象所对应的(动态)代理对象
//因为代理类是动态生成的,所以不确定代理类的类型,因此用其所实现的接口类型
Calculator poxy = (Calculator) proxyFactory.getPoxy();
//调用动态代理对象的方法,该方法是目标对象核心业务方法的增强方法
int addResult = poxy.add(1, 2);
System.out.println(addResult);
}
9.6.3、增强的位置
除了可以在调用目标对象执行功能之前或之后,加入额外的操作之外;
还可以在调用目标对象执行功能发生异常时(catch位置)或在调用目标对象执行功能完毕时(finally位置),加入额外的操作
也就是说,(静态或动态)代理能增强的位置一共有四个
//通过invoke方法来统一管理代理类中的方法该如何执行,该方法有三个参数
/**
* @param proxy:表示代理对象
* @param method:表示要执行的方法
* @param args:表示要执行的方法的参数列表
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
//第1个增强位置:在调用目标对象执行功能之前,加入额外的操作(这里是附加日志功能)
System.out.println("[日志] "+method.getName()+" 方法开始了,参数是:" + Arrays.toString(args));
//固定写法:调用目标对象实现的核心逻辑(最重要的步骤)
result = method.invoke(target, args);
//第2个增强位置:在调用目标对象执行功能之后,加入额外的操作(这里是附加日志功能)
System.out.println("[日志] "+method.getName()+" 方法结束了,结果是:" + result);
} catch (Exception e) {
//第3个增强位置:在调用目标对象执行功能发生异常时,加入额外的操作(这里是附加日志功能)
System.out.println("[日志] "+method.getName()+",异常:"+e.getMessage());
} finally {
//第4个增强位置:在调用目标对象执行功能完毕时,加入额外的操作(这里是附加日志功能)
System.out.println("[日志] "+method.getName()+",方法执行完毕");
}
//固定写法:保证代理对象和目标对象的返回值一致
return result;
}
9.6.4、扩展知识
-
动态代理有两种方式:jdk动态代理(本示例)和cglib动态代理
-
jdk动态代理,要求目标必须实现接口,而且只能对目标所实现的接口方法进行增强
-
jdk动态代理,生成的代理类在com.sun.proxy包下,类名为:$proxy+数字
-
cglib动态代理,不要求目标必须实现接口,生成的代理类会继承目标类,并且和目标类在相同的包下
-
虽然在实际中很少写动态代理的代码,但了解动态代理的思想,对学习Spring的AOP知识很有帮助