您的位置:首页 > 其它

代理模式

2016-06-25 20:23 267 查看

一、概念

  1、定义

  为其他对象提供一种代理以控制对这个对象的访问,在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

  2、优点

真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事物。

代理对象可以在客户端和目标对象之间起到中介作用、

高扩展性

二、代理模式组成

  在代理模式中,通常涉及到下面4中角色:

  ISubject:该接口是对被访问者或被访问资源的抽象

  SubjectImpl:被访问者的具体实现类

  SubjectProxy:被访问者的代理实现类,SubjectProxy持有SubjectImpl的实例

  Client:代表访问者的角色,Client将会访问ISubject类型的对象或资源,Client必须通过ISubject资源的访问代理类SubjectProxy进行

三、代理模式实现方式

  1、静态代理

  SubjectImpl和SubjectProxy都实现了相同的接口,而SubjectProxy内部持有SubjectImpl的引用,当Client通过request()请求服务的时候,SubjectProxy将请求转发给SubjectImpl。在将请求转发给被代理对象SubjectImpl之前或者之后,都可以根据情况插入其他处理逻辑,比如在转发之前记录方法执行开始时间,在转发之后记录结束时间。示例代码如下:

/*
* ISubject角色
*/
public interface Aithmetic
{
public int add(int i,int j);
public int sub(int i,int j);
}


/**
* ISubjectImpl角色
*/
public class AithmeticImpl implements Aithmetic
{
public int add(int i, int j)
{
int result=i+j;
return result;
}
public int sub(int i, int j)
{
int result=i-j;
return result;
}
}


/*
* SubjectProxy角色
*/
public class AithmeticProxy implements Aithmetic
{
private Aithmetic aithmetic;
public AithmeticProxy(Aithmetic aithmetic)
{
this.aithmetic=aithmetic;
}
public int add(int i, int j)
{
//加入自己的逻辑
System.out.println("自定义逻辑开始");
int sum=aithmetic.add(i, j);
return sum;
}
public int sub(int i, int j)
{
System.out.println("自定义逻辑开始");
int sub=aithmetic.sub(i, j);
return sub;
}
}


/*
* Client角色
*/
public class AithmeticProxyTest
{
@Test
public void test()
{
Aithmetic aithmetic=new AithmeticImpl();
AithmeticProxy aithmeticProxy=new AithmeticProxy(aithmetic);
int sum=aithmeticProxy.add(2, 3);
System.out.println(sum);
}
}


  


  静态代理的缺点:针对不一样的目标对象类型,我们要为其单独实现一个代理对象,而实际上,这些代理对象所要添加的横切逻辑是一样的。

  2、动态代理

  我们利用动态代理机制,可以为指定的接口在系统运行期间动态的生成代理对象。

  动态代理机制的实现主要由一个类和一个接口组成,即Java.lang.reflect.Proxy和java.lang.reflect.InvocationHandler接口,下面给出示例为两种不同的类型提供代理对象。

  假设现在有两个接口,都有request方法,我们想在request方法执行之前加入自己的处理逻辑。两个接口如下:

public interface Aithmetic
{
public int add(int i,int j);
public int sub(int i,int j);
public void request();
}


public interface IRequestable
{
public void request();
}


public class AithmeticImpl implements Aithmetic
{
public int add(int i, int j)
{
int result=i+j;
return result;
}
public int sub(int i, int j)
{
int result=i-j;
return result;
}
public void request()
{
System.out.println("执行AithmeticImpl的request函数");
}
}


public class IRequestableImpl implements IRequestable
{

public void request()
{
System.out.println("执行IRequestableImpl的request函数");
}
}


  为了达到目的,我们需要实现一个InvocationHandler:

public class MyInvocationHandler implements InvocationHandler
{

private Object target;
public MyInvocationHandler(Object target)
{
this.target=target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
if(method.getName().equals("request"))
{
System.out.println("加入自己的逻辑");
}
return method.invoke(target, args);
}
}


  然后就可以使用Proxy类,根据MyInvocationHandler的逻辑,为Aithmetic和IRequestable两种类型生成相应的代理对象实例:

public class MyInvocationHandlerTest
{
@Test
public void test()
{
Aithmetic aithmetic=(Aithmetic) Proxy.newProxyInstance(MyInvocationHandlerTest.class.getClassLoader(), new Class[]{Aithmetic.class}, new MyInvocationHandler(new AithmeticImpl()));
aithmetic.request();
System.out.println(aithmetic.add(2,3));

IRequestable iRequestable=(IRequestable) Proxy.newProxyInstance(MyInvocationHandlerTest.class.getClassLoader(), new Class[]{IRequestable.class}, new MyInvocationHandler(new IRequestableImpl()));
iRequestable.request();
}
}


  执行结果为:

  


  动态代理的缺点:动态代理的只能对实现了相应的接口的类使用,如果某个类没有实现任何接口,就无法使用 动态代理机制为其生成相应的动态代理对象。

  3、动态字节码生成

  原理:我们可以对目标对象进行继承扩展,为其生成相应的子类,而子类可以通过覆写来扩展父类的行为,只要将横切逻辑的实现放在子类中,然后让系统使用扩展后的目标对象的子类,就可以达到与代理模式相同的效果了。我们借助于CGLIB这样的动态字节码生成库,在系统运行期间为目标对象生成相应的扩展子类。

  注:需要用到以下三个包

  


  下面是示例代码:

  首先编写需要代理的目标对象:

public class TargetObject
{
public int add(int i, int j)
{
int result = i + j;
return result;
}
}


  创建cglib代理的工厂类:

public class CglibProxy implements MethodInterceptor
{
//设置需要创建子类的类
private Object targetObject;
public Object createProxyInstance(Object target)
{
this.targetObject = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.targetObject.getClass());
//设置回调函数
enhancer.setCallback(this);
//通过字节码技术动态创建子类实例
return enhancer.create();
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable
{
/*obj:目标类实例
*method:目标类法方法的反射对象
*args:方法的动态入参
*methodProxy:代理类实例
*/
System.out.println("加入自己的逻辑");
//通过代理类调用父类中的方法
Object result = methodProxy.invoke(targetObject, args);
System.out.println("操作结束");
return result;
}

}


  测试:

public class CglibProxyTest
{
@Test
public void test()
{
CglibProxy cglibProxy=new CglibProxy();
TargetObject t=(TargetObject) cglibProxy.createProxyInstance(new TargetObject());
System.out.println(t.add(2, 3));
}
}


  执行结果:

  


  注:CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以该类或方法不要声明成final。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: