代理模式在整个设计模式中属于结构类模式,除了代理模式以外还包括我们了解过的适配器模式,装饰模式,组合模式等。他们都是通过组合类或者对象来进一步产生更复杂的结构和逻辑。在java中我们经常使用spring框架进行开发,spring中的AOP的核心就是代理。
代理模式中涉及几个角色:
- 抽象主题角色:定义了被代理角色和代理角色的共同接口或者抽象类。
- 被代理角色:实现或者继承抽象主题角色,定义实现具体业务逻辑的实现。
- 代理角色:实现或者继承抽象主题角色,持有被代理角色的引用,控制和限制被代理角色的实现,并且拥有自己的处理方法(预处理和善后)
JDK代理
在Java中要想实现动态代理机制,需要java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy 类的支持。 我们举个例子,需求是需要在操作数据库的新增数据方法前和后打印输出日志。
public class UserManagerImpl implements UserManager {
@Override
public void addUser(String userId, String userName) {
System.out.println("UserManagerImpl.addUser");
}
}
如上代码我们需要在addUser这个方法执行前和后输出打印日志。 2. 动态代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class LogProxy implements InvocationHandler {
// 目标对象
private Object targetObject;
//绑定关系,也就是关联到哪个接口(与具体的实现类绑定)的哪些方法将被调用时,执行invoke方法。
public Object newProxyInstance(Object targetObject){
this.targetObject=targetObject;
//该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
//第一个参数指定产生代理对象的类加载器,需要将其指定为和目标对象同一个类加载器
//第二个参数要实现和目标对象一样的接口,所以只需要拿到目标对象的实现接口
//第三个参数表明这些被拦截的方法在被拦截时需要执行哪个InvocationHandler的invoke方法
//根据传入的目标返回一个代理对象
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),this);
}
@Override
//关联的这个实现类的方法被调用时将被执行
/*InvocationHandler接口的方法,proxy表示代理,method表示原对象被调用的方法,args表示方法的参数*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object ret=null;
try{
/*原对象方法调用前处理日志信息*/
System.out.println("开始调用");
//调用目标方法
ret=method.invoke(targetObject, args);
/*原对象方法调用后处理日志信息*/
System.out.println("调用结束");
}catch(Exception e){
e.printStackTrace();
throw e;
}
return ret;
}
}
调用
LogProxy logProxy=new LogProxy();
UserManager userManager=(UserManager)logProxy.newProxyInstance(new UserManagerImpl());
userManager.addUser("1", "三");
cglib代理
如果使用cglib代理,那么需要先引用cglib的依赖。
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.10</version>
</dependency>
那么创建一回调拦截器,实现 MethodInterceptor接口,用于处理子类代理调用方法时回调的逻辑,也即真正代理的逻辑。
public class ToolProxyCallback implements MethodInterceptor {
// 目标对象
private Object target;
public ToolProxyCallback(Object target) {
this.target = target;
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
// 入参日志打印
System.out.println("准备执行目标方法;参数信息为="+args);
// 权限拦截
if(args.length <= 2) { // 假设这里的权限是参数不能小于2个
return null;
}
// 通过反射执行目标方法
Object resultObj = method.invoke(target,args);
// 处理接口打印
System.out.println("目标方法请求结果为;"+resultObj);
return resultObj;
}
}
还需要一个工厂来创建子类代理的实例。
public class ToolProxyFactory {
/**
* 获取子类代理实例
* @param target 目标对象
* @param callback 回调接口
* @return
*/
public static Object getProxyInstance(Object target, Callback callback) {
// 工具类
Enhancer enhancer = new Enhancer();
// 设置父类
enhancer.setSuperclass(target.getClass());
// 设置回调函数。
enhancer.setCallback(callback);
return enhancer.create(); // 创建子类代理对象
}
}
那么调用目标方法就变为这样。
public void testProjectProxy() {
ToolService service = new ToolService();
Callback toolProxyCallback = new ToolProxyCallback(service);
ToolService serviceProxy = (ToolService)ToolProxyFactory.getProxyInstance(service,toolProxyCallback);
/**
* 使用 ToolProxyFactory 构建出 ToolCglibService的代理子类,通过代理子类去调用接口方法
*/
String[] args = new String[]{"-s","test","-n","zhangsan"};
serviceProxy.run(args);
}