您的位置:首页 > 编程语言 > Java开发

java proxy InvocationHandler 模拟 spring aop

2014-07-25 12:52 375 查看
在学习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方法,那么就成功对被代理类的方法进行了织入。所以上面的问题也就解决了。从而动态代理的接口方法也就实现了。这也就是动态代理的过程啦。

如有不对的地方大家一起交流。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息