首页 > 代码库 > Spring源码阅读:Spring AOP设计与实现(一):动态代理

Spring源码阅读:Spring AOP设计与实现(一):动态代理

    在Spring的有两个核心:IOC与AOP,AOP又是基于动态代理模式实现的。所以要了解SpringAOP是如何设计的之前,还是先了解一下Java中的动态代理比较好。

 

认识代理模式

 

代理模式是这么描述的

代理模式是为其他对象提供一种代理以控制对这个对象的访问

 

代理对象的功能

通过创建一个代理对象,用这个代理对象去代理真实的对象,客户端得到这个代理对象后,对客户端并没有什么影响,就跟真实的对象一样(因为代理对象和真是对象实现了同一接口)。

 

下面看看代理模式的类图

 

 

解说:

   

    RealSubject是真实对象。

    Proxy是代理者,他来代理RealSubject,表现在Proxy对象拥有RealSubject实例,真正执行的还是realSubject.request()。

    Client,代理模式的客户,他是直接与Subject接口打交道。

    Proxy与RealSubject实现了同一接口Subject,所以Client看到的Proxy就跟看到了RealSubject一样。

 

对代理模式分析一下:

举一个现实中的例子:现实生活中有很多专卖店,手机提供商等。

 

做手机的:中华酷联、小米、三星、苹果、魅族等等。

做家电的:海尔、美的等等。

他们其实就是真是的对象,提供手机的。

 

各大品牌专卖店:海尔专卖店、诺基亚专卖店、三星专卖店、苹果专卖店

他们其实就是代理商,他们不提供手机,他们提供的是额外的服务,例如和电信运营商结合提供买手机送话费服务。

 

 

 

实例说明

// 接口Foo就充当代理模式中的Subject角色public interface Foo {    public void sayFoo(String name);}  // FooImpl充当了RealSubject角色,对Foo提供的方法做了具体实现public class FooImpl implements Foo{    public void sayFoo(String name) {        System.out.println("手机卖给 "+name);    }} // FooProxy是代理者public class FooProxy implements Foo{    Foo foo=null;    public FooProxy(Foo foo){        this.foo=foo;    }// 处理请求时,还是有真实的对象来处理的    public void sayFoo(String name) {        if(foo!=null){            foo.sayFoo(name);        }    }} // 客户端调用public class Client {    public static void main(String[] args){         Foo proxy=new FooProxy(new FooImpl());         proxy.sayFoo("zhang san");    }} // 执行结果://手机卖给 zhang san 
View Code

 

如果只是像上面那样使用代理模式,还不如不使用代理模式。

代理模式:用于控制对真实对象的访问。这种控制是多方面的,实际应用中,代理模式又被分为下列几种:

 

 

就拿最后一种来说吧,智能引用,在访问对象时附加一些操作(这块AOP中要用到)。

接下来,专卖店(代理商)对象要提供一些附加功能:

 

public class FooProxy implements Foo{    Foo foo=null;    public FooProxy(Foo foo){        this.foo=foo;    }    public void sayFoo(String name) {        if(foo!=null){            before();            foo.sayFoo(name);            after();        }    }     public void before(){        System.out.println("before: 介绍手机,介绍服务 .....");    }     public void after(){        System.out.println("after: 送话费 .....");    }}
View Code

 

在真实的对象处理请求的前后,附加了两个功能:before(),after()。Client的代码不需要改变,执行的结果是:

before: 介绍手机,介绍服务 .....手机卖给 zhang sanafter: 送话费 .....
View Code

 

这样就达到了附加功能的目的,这样手机就卖的多了。

 

 

动态代理模式

 

    AOP使用了代理模式,但并非这个,这个代理模式是设计模式中的代理模式,在Java中有一种特有的代理模式,也称为动态代理模式。

 

假若上面的例子是卖手机的,现在系统中要有卖家电的,那我可以在系统中添加如下设计:

做法还是这样的:

public interface Hello {    public void sayHello(String hello);} public class HelloImpl implements Hello {    public void sayHello(String hello) {        System.out.println("hello, "+hello);    }} public class HelloProxy implements Hello{    Hello hello;    public HelloProxy(Hello hello){         this.hello=hello;    }    public void sayHello(String hello) {         this.hello.sayHello(hello);    }} public class Client {    public static void main(String[] args){         Foo proxy=new FooProxy(new FooImpl());         proxy.sayFoo("zhang san");          Hello hello=new HelloProxy(new HelloImpl() );         hello.sayHello("li si");    }}
View Code

 

    如果有更多的呢,例如要加入卖床上用品,卖办公用品,卖相机等数码产品。。。。

    提供商直接与客户打交道,这事是很困难的,操作性不好,肯定得有代理商的参与。难道在系统中都为他们设计一个代理?

    上面的例子中,一个代理商只代理一种产品,代理商太多的话,提供商与代理商打交道也麻烦,客户与代理商打交道也麻烦,那么多该选哪一个呀?

    对于代理商来说,只代理一样产品,对那样产品的依赖性太大了,那样小命就捏在提供商手里了,最重要的是不是很赚钱。因此就会想着要多代理几样产品。

    于是商城就出现了,例如国美,京东等,这里不去管国美,京东到底是怎样操作的,只是为了理解动态代理需要。

   

    那么商城反映到程序中就是:

 

public class FooProxy implements Foo, Hello ,,,,更多接口{    Foo foo=null;    Hello hello=null;    // 更多真实对象     public FooProxy(Foo foo){        this.foo=foo;    }    public FooProxy(Hello hello){        this.hello=hello;    }
View Code

 

这样一来,一个大的代理商(商城)就出现了,可以代理很多产品了。

 

    这样一来,业务实现了,但是我们程序员悲催了。尼玛呀,每添加一类商品,程序猿就得调整一个或者或者多个xxxProxy类。这样程序员太累,这样的设计也违反了开闭原则。

    咋办呢,那些大牛们就根据JVM的特性和ClassLoader设计出来动态代理。使用动态代理,可以动态的生成xxxProxy类呢,这样就避免了编程的方式了。

   

    动态代理涉及到了一个接口和一个类:InvocationHandler、Proxy

Proxy就是代理了,Proxy的对象就是上面程序中的fooProxy,helloProxy。同时他也提供了生成代理类的静态方法,生成代理对象的静态方法。

    InvocationHandler就是利用反射调用真实对象的接口。

 

现在利用动态代理来改造上面程序,Foo接口,FooImple用做调整。附加一个Handler就行了:

public class MyInvokerHandler implements InvocationHandler {    private Foo foo;    public MyInvokerHandler(){}    public MyInvokerHandler(Foo foo){        this.foo=foo;    }    public void beforeInvoke(){        System.out.println("doSomething before invoke");    }    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        beforeInvoke();        method.invoke(foo,args); // 通过反射调用        afterInvoke();        return null;    }    public void afterInvoke(){        System.out.println("doSomething after invoke");    }} // Client程序调整为:public class Client {    public static void main(String[] args){        FooImpl foo=new FooImpl();        MyInvokerHandler handler=new MyInvokerHandler(foo);        // proxy是代理对象,它既是Proxy的对象,也是Foo的对象        Object proxy=Proxy.newProxyInstance(Client.class.getClassLoader(),new Class[]{Foo.class},handler);        Foo fooProxy=(Foo)proxy;        fooProxy.sayFoo("zhang san");     }} // 程序执行结果:doSomething before invoke手机卖给 zhang sandoSomething after invoke
View Code

 

这样不用写代理类就完成了上面的功能。

要让它也实现Hello接口呢 ?

再对上面的程序调整:

public class MyInvokerHandler implements InvocationHandler {    private Foo foo;    private Hello hello;     public MyInvokerHandler(){}    public MyInvokerHandler(Foo foo){        this.foo=foo;    }     public void setFoo(Foo foo) {        this.foo = foo;    }     public void setHello(Hello hello) {        this.hello = hello;    }     public void beforeInvoke(){        System.out.println("doSomething before invoke");    }     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        beforeInvoke();        System.out.println(method.getName());        if(method.getName().equals("sayHello") && proxy instanceof Hello)    {            method.invoke(hello,args); // 通过反射调用        }else if(method.getName().equals("sayFoo") && proxy instanceof Foo){            method.invoke(foo,args);        }        afterInvoke();        return null;    }    public void afterInvoke(){        System.out.println("doSomething after invoke");    }} //Client调整为:public class Client {    public static void main(String[] args){        FooImpl foo=new FooImpl();        HelloImpl hello=new HelloImpl();         MyInvokerHandler handler=new MyInvokerHandler();        handler.setFoo(foo);        handler.setHello(hello);         // proxy是代理对象,它既是Proxy的对象,也是Foo的实例  ,还是Hello的实例        Object proxy=Proxy.newProxyInstance(Client.class.getClassLoader(),new Class[]{Foo.class,Hello.class},handler);        Foo fooProxy=(Foo)proxy;        fooProxy.sayFoo("zhang san");         Hello helloProxy=(Hello)proxy;        helloProxy.sayHello("li si");     }} //执行结果是:doSomething before invokesayFoo手机卖给 zhang sandoSomething after invokedoSomething before invokesayHellohello, li sidoSomething after invoke  
View Code

 

// 如果还要添加更多功能,只需要调整这个Handler即可。

 

猜想动态生成的代理类

 

现在可以猜测一下,动态生成的代理类到底是什么样的呢?

public ProxyClass extends Proxy implement Foo, Hello{    InvocationHandler handler;    public ProxyClass(InvocationHandler handler){        this.handler=handler;    }     private execute(String methodName, Object[] args){          Method method=this.getClass().getMethod(methodName);          Handler.invoke(this, method, args);    }      public void sayFoo(String name){          Object[] args=new Object[]{name};          execute(this, "sayFoo", args);     }      public void sayHello(String hello){          Object[] args=new Object[]{hello};          execute(this, "sayHello", args);     }}
View Code