Spring AOP 实例解析(InvocationHandler 的invoke的proxy 参数作用)

用动态代理实现面向切面编程,以下实例实现在特定方法前后添加日志和事务的的功能。

1)Proxy 类 (真实对象的代理) 的三个参数

    前两个参数用于生成$Proxy 的构造器,此构造器再以invocationHandler 为参数生成$Proxy 实例。

  • classLoader: 类加载器,它由真实对象userService 得到,但其实跟userService 不是一一对应的关系;用任何一个对象都可以用同样的方法得到一样的类加载器;既然如此,用测试类本身也可以得到类加载器:this.getClass().getClassLoader(),再把this 省略,就变成了getClass().getClassLoader()
    类加载器打印出来就是:sun.misc.Launcher$AppClassLoader@18b4aac2
  • interfaces: 接口数组,真实对象userService 所实现的所有接口。Proxy 用类加载器和接口数组这两个参数得到动态生成的Proxy 的Class 对象(getProxyClass0(loader, intfs)),再用此Class 对象获取其构造器(cl.getConstructor(constructorParams)),由构造器生成Proxy 实例(cons.newInstance(new Object[]{h}), 此处的h 就是Proxy 第三个参数invocationHandler). 
  • invocationHandler: 直译是调用处理器,它这个对象本质是Proxy 类的代理,也就是真实对象的代理 的代理。Proxy类实现了真实对象的接口,所以它的对象可以调用真实对象的方法,调用时是指派invocationHandler 去实际执行系统增强业务(即日志、事务等) 和真实业务。

2)InvocationHandler 的invoke 三个参数的作用

  • proxy: 就是Proxy 的一个动态实例,用Idea debug 显示为:{$Proxy4@862} com.qf.service.impl.UserServiceImpl@5a8806ef. 这个参数在invoke 方法体内可以完全不用,所以很难理解它的作用,甚至知乎、Stackoverflow 上的回答都感觉不太对。Stackoverflow 上一个回答说作用是可以将代理对象返回以进行连续调用,并写了demo(https://stackoverflow.com/questions/22930195/understanding-proxy-arguments-of-the-invoke-method-of-java-lang-reflect-invoca),难道不需要连续调用的话就没用了吗?又查了很多资料,终于找到了一个比较符合逻辑的解释:invoke 第二个参数是method 怎么来的?$Proxy 动态实例 (即第一个参数proxy) 生成后(是class 文件),通过反向编译,可以看到里面有如下一段静态代码块(来源:http://rejoy.iteye.com/blog/1627405),也就是说只有proxy 实例在InvocationHandler 实现类里加载才能产生第二个参数method (静态代码块是虚拟机加载类的时候执行的,而且只执行一次),所以$Proxy 实例要把自己传给InvocationHandler 的invoke 方法。
m3 = Class.forName("dynamic.proxy.UserService").getMethod("add", new Class[0]);

  • method: 真实对象要实现的业务方法,由$Proxy 实例的静态代码块得到。
  • args: 第二个参数method 的参数。

3)两个概念:系统增强服务(日志、事务、权限等) 与系统真实业务分离,放到 InvocationHandler 实现类invoke 方法里面的 这些出代码片段就是一个切面,本文Demo 中真实业务add() 就是切入点

以下为InvocationHandler 实现类和测试类(含创建$Proxy 动态实例) 的代码。

public class DynamicProxy implements InvocationHandler {
	private TransactionManager tx;
	private LoggerManager log;
	private Object object;

	public DynamicProxy() {
	}
        //object 参数为真实对象,此例中为userService 对象
	public DynamicProxy(TransactionManager tx, LoggerManager log, Object object) {
		this.tx = tx;
		this.log = log;
		this.object = object;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		tx.begin();
		log.beginLog();
		Object invoke = method.invoke(object, args);
		log.endLog();
		tx.commit();
		return invoke;
	}
}
        @Test
	public void testDynamicAOP(){
		LoggerManager log = new LoggerManager();
		TransactionManager tm = new TransactionManager();
		IUserService userService = new UserServiceImpl();
		ClassLoader loader = userService.getClass().getClassLoader();
		Class<?>[] interfaces = userService.getClass().getInterfaces();
		InvocationHandler handler = new DynamicProxy(tm, log, userService);
		IUserService userServiceProxy = (IUserService) Proxy.newProxyInstance(loader, interfaces, handler);
		userServiceProxy.add(new User("Rock"));
	}

猜你喜欢

转载自blog.csdn.net/rock154/article/details/80059344