前言
所谓代理其实就是代你打理一些事情,比如你选择了一个三天两晚的特色主题游产品。那么你需要做的仅仅是交钱就好,剩下的机票酒店签证路途门票等一系列事情,旅行社会帮你搞定。
动态代理技术在Spring和Mybatis中应用十分广泛,举个例子我们平时写代码只需要编写增删改查的强业务关联代码即可,至于开关数据库连接,事物回滚等操作,都是基于代理的方式去帮我们搞定。代理方法会在我们的sql执行前,执行后,及有无异常出现的状态中,帮我们进行各种可以无业务关联的且必须的操作。
实践
下面以一个最简单的Demo来实现一个基本的JDK代理功能:
首先准备如下类文件:
1、用户管理接口,添加增删改查方法
package service;
public interface IUserManager {
public void addUser();
public void delUser();
public void updateUser();
public void queryUser();
}
2、用户接口实现类。
package service;
public class UserManagerImpl implements IUserManager{
@Override
public void addUser() {
System.out.println("新增用户");
}
@Override
public void delUser() {
System.out.println("删除用户");
}
@Override
public void updateUser() {
System.out.println("更新用户");
}
@Override
public void queryUser() {
System.out.println("查询用户");
}
}
3、添加JDK动态代理类
package service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxyForUser implements InvocationHandler{
private IUserManager iUserManager = null;
//创建一个生成代理对象的方法
public IUserManager newUserManagerProxy(IUserManager iUserManager) {
this.iUserManager = iUserManager;
return (IUserManager) Proxy.newProxyInstance(iUserManager.getClass().getClassLoader(), iUserManager.getClass().getInterfaces(), this);
}
//实现invoke方法,完成对被代理的类中 每一个方法的代理内容,也就是增加一些额外的逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入代理方法中");
Object o = method.invoke(iUserManager, args);
System.out.println("在usermanager执行之后操作");
return o;
}
}
4、添加Main方法进行测试
package main;
import service.IUserManager;
import service.JDKProxyForUser;
import service.UserManagerImpl;
public class MainControl {
public static void main(String[] args) {
JDKProxyForUser jpu = new JDKProxyForUser();
IUserManager iUserManagerProxy = jpu.newUserManagerProxy(new UserManagerImpl());
iUserManagerProxy.addUser();
iUserManagerProxy.delUser();
iUserManagerProxy.queryUser();
iUserManagerProxy.updateUser();
}
}
5、控制台输出结果:
进入代理方法中
新增用户
在usermanager执行之后操作
进入代理方法中
删除用户
在usermanager执行之后操作
进入代理方法中
查询用户
在usermanager执行之后操作
进入代理方法中
更新用户
在usermanager执行之后操作
至此一个最简单的代理方案出炉了。
代码解析
初学者可以跟我一样,用debug去观察一下内部实现流程。下面我也会做一些总结。
通过观察Main中的代码
IUserManager iUserManagerProxy = jpu.newUserManagerProxy(new UserManagerImpl());
iUserManagerProxy.addUser();
我们可以发现其实调用addUser的还是一个IUserManager类接口,但是却实现了更加丰富的功能,所以不难想象动态代理技术帮我们丰富了接口的实现方式
(1)首先我们的JDK动态代理类要实现InvocationHandler接口,接口里只有一个invoke方法,我们就是要去实现这个方法,这是第一步
public interface InvocationHandler {
/**
......
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
我们可以看到invoke方法有三个参数,分别是(Object proxy, Method method, Object[] args)
Object proxy:@param proxy the proxy instance that the method was invoked on,也就是说这个参数是代理后的那个对象
Method method:被代理的对象的方法,例如当我调用addUser()方法时,这个method就是addUser
Object[] args:调度方法的参数,如果addUser里面有VO参数,那么这里面就会出现这个参数
之后就可以可以添加自己的方法了。
(2)生成代理对象
return (IUserManager) Proxy.newProxyInstance(iUserManager.getClass().getClassLoader(), iUserManager.getClass().getInterfaces(), this);
重点看这一段,newProxyInstance构造器中有三个参数:
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
......
}
这里也有三个参数:ClassLoader loader, Class<?>[] interfaces, InvocationHandler h
ClassLoader loader:@param loader the class loader to define the proxy class
类加载器参数,本例中加载的对象是IUserManager的实现类的加载器。
Class<?>[] interfaces:@param interfaces the list of interfaces for the proxy class to implement
把实现类的接口类List列举出来,与实现类做关联
InvocationHandler h:@param h the invocation handler to dispatch method invocations to
传一个实现类invoke方法的动态代理类
(3)通过代理对象调用代理后的方法即可
随着笔者学习的深入后续还会进行一些更深层次的编程之旅