首页 > 代码库 > java proxy InvocationHandler 模拟 spring aop

java proxy InvocationHandler 模拟 spring aop

在学习spring的aop的时候,老师叫我们使用java的proxy和InvocationHandler来模拟spring的aop。

首先要了解什么是代理:所谓代理就是我想让小王去买包烟,但是我又不想直接通知小王,因为那样我感觉自己非常的掉价。所以我就叫小李去通知小王,让小王完成这件事。在这个过程中,我是一个主动方,小王是一个行为执行方,而小李就是一个代理。因为小李负责我和小王之间的关系,甚至小李也可以叫小王给自己再买一包烟(实际这就是动态代理的最大用处)。

动态代理模式有代理对象,被代理对象。而在代理模式中还需要注意的一点就是,我们生成的代理对象,一般是要和被代理对象使用相同的接口的,这样就可以面向接口编程,所有被代理对象有的方法,我们生成的代理对象也都有,并且方法的功能还增强了。


下面就用代码模拟一下:

package cn.wsy.dao;
/**
 * 
 * 项目名称 spring_aop
 * 作者  tim
 * 创建时间 2014-7-25
 * 类描述 用户dao接口
 */
public interface UserDao {
	/**
	 * 保存
	 */
	public void save();
	
	/**
	 * 删除
	 */
	public void delete();
}

package cn.wsy.dao.impl;

import cn.wsy.dao.UserDao;
/**
 * 
 * 项目名称 spring_aop
 * 作者  tim
 * 创建时间 2014-7-25
 * 类描述 UserDao接口的实现类
 */
public class UserDaoImpl implements UserDao {

	@Override
	public void save() {
		System.out.println("UserDaoImpl save start...");
	}

	@Override
	public void delete() {
		// TODO Auto-generated method stub
		System.out.println("UserDaoImpl delete start...");
	}

}

package cn.wsy.interceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Date;
/**
 * 
 * 项目名称 spring_aop
 * 作者  tim
 * 创建时间 2014-7-25
 * 类描述 将需要织入的方法织入到被代理对象调用方法的前后
 */
public class LogInterceptor implements InvocationHandler{
	/**被代理对象**/
	private Object target;
	
	/**需要织入的方法**/
	public 	void beforeMethod(Method method){
		System.out.println(method.getName()+"start"+new Date());
	}
	
	/**
	 * proxy 代理实例,一般用不到
	 * method 代理实例的方法,通过它可以对目标代理类进行发射调用
	 * args 代理实例的方法的参数
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		// TODO Auto-generated method stub
		//织入方法
		beforeMethod(method);
		
		//执行被代理对象的方法
		method.invoke(target, args);
		return null;
	}

	public Object getTarget() {
		return target;
	}

	public void setTarget(Object target) {
		this.target = target;
	}
	
}

package cn.wsy.test;

import java.lang.reflect.Proxy;

import cn.wsy.dao.UserDao;
import cn.wsy.dao.impl.UserDaoImpl;
import cn.wsy.interceptor.LogInterceptor;
/**
 * 项目名称 spring_aop
 * 作者  lenovo
 * 创建时间 2014-7-25
 * 类描述 使用jdk 的proxy和 InvocationHandler模拟spring的aop
 */
public class AopTest {
	public static void main(String[] args) {
		UserDao userDao = new UserDaoImpl();
		LogInterceptor log = new LogInterceptor();
		log.setTarget(userDao);
		
		/**
		 * 第一个参数是被代理对象的加载器,必须和被代理对象使用一个类加载器
		 * 第二个参数是代理对象实现的接口,该接口被代理对象也实现,保证返回的是面向接口的编程
		 * 第三个参数是派生出来的代理处理程序
		 */
		UserDao userDaoProxy = (UserDao) Proxy.newProxyInstance(
				UserDao.class.getClassLoader(), new Class[] { UserDao.class },
				log);
		userDaoProxy.delete();
		userDaoProxy.save();
		
	}
}

代码如上所示。下面是自己的一些见解,在main方法中我们使用Proxy的newProxyInstance()静态方法。在这个方法中有三个参数,上面已经说明,不在累赘。现在说明一下这个userDaoProxy对象 的方法调用是如何实现方法增强的。

首先我们的Proxy代理对象一个实现了和被代理对象相同的接口的,由此可知,我们的代理对象也拥有被代理对象的方法。那么问题在于代理对象的这些方法是怎么实现的呢。

我们肯定会想到它一定是调了InvocationHandler中的invoke方法。而在该方法中最主要的就是Method和args两个参数。如果得到这两个参数,那么代理对象调用InvocationHandler中的invoke方法就没有问题了。在Proxy的参数中有一个类启动器的参数,通过这个参数我们就可以得到调用的方法。例如:

userDaoProxy中也有一个save方法,那么

UserDao.class.getMethod就可以得到调用的方法名,那得到方法当然就可以得到参数了,从而就可以调用InvocationHandler中的invoke方法,那么就成功对被代理类的方法进行了织入。所以上面的问题也就解决了。从而动态代理的接口方法也就实现了。这也就是动态代理的过程啦。

如有不对的地方大家一起交流。