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

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

 

认识代理模式

 

代理模式是这么描述的

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

 

代理对象的功能

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

 

下面看看代理模式的类图

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

 

解说:

   

    RealSubject是真实对象。

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

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

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

 

对代理模式分析一下:

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

 

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

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

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

 

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

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

 

 

 

实例说明

Spring源码阅读:Spring AOP设计与实现(一):动态代理
// 接口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

 

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

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

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

 

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

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

 

Spring源码阅读:Spring 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的代码不需要改变,执行的结果是:

Spring源码阅读:Spring AOP设计与实现(一):动态代理
before: 介绍手机,介绍服务 .....

手机卖给 zhang san

after: 送话费 .....
View Code

 

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

 

 

动态代理模式

 

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

 

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

做法还是这样的:

Spring源码阅读:Spring AOP设计与实现(一):动态代理
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

 

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

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

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

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

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

   

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

 

Spring源码阅读:Spring AOP设计与实现(一):动态代理
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就行了:

Spring源码阅读:Spring AOP设计与实现(一):动态代理
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 san

doSomething after invoke
View Code

 

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

要让它也实现Hello接口呢 ?

再对上面的程序调整:

Spring源码阅读:Spring AOP设计与实现(一):动态代理
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 invoke

sayFoo

手机卖给 zhang san

doSomething after invoke

doSomething before invoke

sayHello

hello, li si

doSomething after invoke

 

 
View Code

 

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

 

猜想动态生成的代理类

 

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

Spring源码阅读:Spring AOP设计与实现(一):动态代理
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

 

Spring源码阅读:Spring AOP设计与实现(一):动态代理,布布扣,bubuko.com

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

上一篇:业务线移动端适配方案总结


下一篇:java基础知识回顾之---java String final类普通方法的应用之“两个字符串中最大相同的子串”