代理模式
代理模式
代理模式是常用设计模式之一,当一个对象不适合或者不能直接引用另一个对象时,使用代理对象做中介,通过代理对象访问目标对象。 并且可在代理对象中扩展目标对象的功能
如同经纪人代办事情一样,客户通过代理对象访问目标对象,可以实现权限的控制。同时代理对象可以代处理一些复杂的事务,减轻目标对象的负担。
java中代理模式有三种实现:
静态代理
- 假设我们有一个client对象需要访问target目标对象请求一些事务处理,client无法直接访问target,只能通过我们提供的Myproxy代理对象:
- 创建目标类的接口
ITarget.java
- 提供一个
hadleThings
事件处理方法
- 提供一个
package cc.ggbond.proxy;
public interface ITarget {
public void handleThings();
}
- 创建目标类
Target.java
- 目标类实现ITarget接口 实现其中的处理方法.
package cc.ggbond.proxy;
public class Target implements ITarget{
@Override
public void handleThings() {
// TODO Auto-generated method stub
System.out.println("目标对象处理...");
}
}
- 创建代理类
MyProxy.java
- 代理类需要与目标类实现相同的接口,重写方法,可在此处扩展目标对象的功能。
- 在类中维护一个目标类对象的引用,通过这个引用来访问目标对象的方法。
package cc.ggbond.proxy;
public class MyProxy implements ITarget{
private static ITarget target = new Target(); ;
@Override
public void handleThings() {
System.out.println("代理对象预处理...");
target.handleThings();
System.out.println("代理对象处理结束...");
}
}
- 创建客户类使用代理对象实现需要的操作:
package cc.ggbond.proxy;
import org.junit.Test;
public class Clinet {
@Test
public void testProxy() {
ITarget proxy = new MyProxy();
proxy.handleThings();
}
}
运行结果:
代理对象预处理… 目标对象处理… 代理对象处理结束…
可见客户通过代理对象实现了目标对象的功能,并且在代理对象中扩展了功能。实现预处理和善后。
- 缺点:如果接口和需要代理的类增多, 需要为每一个类创建一个代理类。代码量多。 如果目标类扩展方法,代理类需要同时扩展,不易维护。
动态代理
动态代理解决了静态代理不易维护和代理类多的缺点。动态生成代理对象。仅需一个代理工厂类
java中主要有两种动态代理方式:
JDK提供的Proxy类
还是上面的例子,Target类 和 ITarget类保持不变
- 代理类
MyProxy.java
修改如下:
package cc.ggbond.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; //jdk 反射包中提供代理类
public class MyProxy<T>{
private T target; //维护目标对象的引用,通过构造函数传入
public MyProxy(T target) {
this.target = target;
}
//获取代理对象的方法
public Object getProxyInstance() {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(), //第一个参数是目标对象的类加载器
target.getClass().getInterfaces(), //目标对象实现的接口
//回调接口,对于目标对象的每个方法,通过反射获取方法参数
//然后回调访问这个接口的invoke方法
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在此处扩展目标类的功能
System.out.println("代理开始....");
if(method.getName().equals("save")) {
Object returnValue = method.invoke(target, args);
System.out.println("代理结束....");
return returnValue;
}
return null;
}
});
}
}
- 然后客户端使用代理方法如下:
package cc.ggbond.proxy;
import org.junit.Test;
public class Clinet {
@Test
public void testProxy() {
ITarget proxy = (ITarget) new MyProxy(new Target()).getProxyInstance();
proxy.handleThings();
}
}
- 运行结果:
代理开始…. 目标对象处理… 代理结束….
- 可以发现动态代理的优点,不用实现与目标类相同的接口,仅需一个代理类,几乎可以代理所有类和方法
- 这个代理有一个缺陷是要求被代理的类需要是实现了接口的类。如果目标类没有实现任何接口,不能用这种方式代理
Spring核心包中的Cglib代理
Cglib代理不需要目标类实现接口.
Cglib代理封装在了封装在spring核心包spring-core
中.使用需要先导入此包。
Cglib产生的代理对象是目标对象的子类
Calib代理广泛应用于Aop
使用cglib代理MyProxy.java
如下:
package cc.ggbond.proxy;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
//代理类需要实现MethodInterceptor接口
public class MyProxy <T> implements MethodInterceptor{
T taget;
public MyProxy(T taget) {
super();
this.taget = taget;
}
//获取代理对象实例
public Object getProxyInstance() {
//通过这个Enhancer增强工厂来创建代理对象
Enhancer en = new Enhancer();
//设置代理对象的父类
en.setSuperclass(taget.getClass());
//设置访问方法时的回调接口
en.setCallback(this);
//创建代理对象并返回
return en.create();
}
//重写intercept方法,这个是代理对象的回调方法
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
// TODO Auto-generated method stub
System.out.println("cglib代理开始...");
Object returnValue = arg1.invoke(taget, arg2);
System.out.println("cglib代理结束...");
return returnValue;
}
}
-
客户端使用代理对象方法同上一个不变。
-
运行结果:
cglib代理开始… 目标对象处理… cglib代理结束…
- 上一篇 leetcode-15-3sum
- 下一篇 ctguoj-cli校oj命令行版