好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

Java的动态代理和静态代理详解

0、代理模式

为什么要学习代理模式?这是SpringAOP的底层【SpringAOP和SpringMVC】

代理模式的分类:

静态代理 动态代理

1、静态代理

静态代理中,我们对目标对象的每个方法的增强都是手动完成的(后面会具体演示代码_),非常不灵活(比如接口一旦新增加方法,目标对象和代理对象都要进行修改)且麻烦(_需要对每个目标类都单独写一个代理类 )。 实际应用场景非常非常少,日常开发几乎看不到使用静态代理的场景。

角色分析:

抽象角色:一般会使用接口或者抽象类来解决 真实角色:被代理的角色 代理角色:代理真实角色,代理真实角色后,我们一般会做一些附属操作 客户:访问代理对象的人!

代码步骤:

1、接口

?

1

2

3

public interface Rent {

     public void rent();

}

2、真实角色

?

1

2

3

4

5

6

//房东

public class Host implements Rent {

     public void rent() {

         System.out.println( "房东要租房子" );

     }

}

3、代理角色

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

public class Proxy implements Rent{

     private Host host;

     public Proxy() {

     }

     public Proxy(Host host) {

         this .host = host;

     }

     public void rent(){

         seeHouse();

         host.rent();

         fare();

     }

     //看房

     public void seeHouse(){

         System.out.println( "中介带你看房" );

     }

     //收中介费

     public void fare(){

         System.out.println( "中介收费" );

     }

}

4、客服端访问代理角色

?

1

2

3

4

5

6

7

8

public class Client {

     public static void main(String[] args) {

         Host host = new Host();

         //代理,代理角色一般会有附属操作!

         Proxy proxy = new Proxy(host);

         proxy.rent();

     }

}

代理模式的好处:

可以使真实角色的操作更加纯粹!不用去关注一些公共的业务 公共也就交给代理角色!实现业务的分工! 公共业务发生扩展的时候,方便集中管理!

缺点:

一个真实角色会产生一个代理角色;从JVM角度来看,静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的class文件。

2、 加深理解

AOP,的底层代理模式

3、动态代理

动态代理和静态代理角色一样 动态代理的代理类是动态生成的,不是我们直接写好的! 动态代理分为两大类:基于接口的动态代理,基于类的动态代理 基于接口——JDK动态代理 基于类:cglib动态代理 java字节码实现:javasist

需要了解两个类:Proxy: 代理类,InvocationHandler : 调用处理程序

从 JVM 角度来说,动态代理是在运行时动态生成类字节码,并加载到 JVM 中的。

?

1

2

//Proxy是生成动态代理类,提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。

//InvocationHandler-- invoke 调用处理程序并返回接口, 是由代理实例的调用处理程序实现的接口 。

动态代理的好处:

可以使真实角色的操作更加纯粹!不用去关系一些公共的业务 公共也就交给代理角色!实现

?

1

2

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h){

}

1. loader   :类加载器,用于加载代理对象。

2. interfaces  : 被代理类实现的一些接口;

3. h  : 实现了  InvocationHandler  接口的对象;

要实现动态代理的话,还必须需要实现 InvocationHandler  来自定义处理逻辑。 当我们的动态代理对象调用一个方法时,这个方法的调用就会被转发到实现 InvocationHandler  接口类的  invoke  方法来调用。

?

1

2

3

public interface InvocationHandler {

     Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

}

1. proxy :动态生成的代理类

2. method : 与代理类对象调用的方法相对应

3. args : 当前 method 方法的参数

动态代理的例子

1、定义接口

?

1

2

3

public interface Rent {

     public void rent();

}

2、实现租房的接口

?

1

2

3

4

5

6

public class Host implements Rent {

     @Override

     public void rent() {

         System.out.println( "房东要租房" );

     }

}

3、定义一个JDK动态代理类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

public class DebugInvocationHandler implements InvocationHandler {

     /**

      * 代理类中的真实对象

      */

     private final Object target;

     public DebugInvocationHandler(Object target){

         this .target = target;

     }

     /**

      * 当你使用代理对象调用方法的时候实际会调用到这个方法

      */

     @Override

     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

         //调用方法前

         System.out.println( "before method" + method.getName());

         Object res = method.invoke(target, args);

         //调用方法后

         System.out.println( "after method" + method.getName());

         return res;

     }

}

invoke()  方法: 当我们的动态代理对象调用原生方法的时候,最终实际上调用到的是  invoke()  方法,然后  invoke()  方法代替我们去调用了被代理对象的原生方法。

4、获取代理对象的工厂类

?

1

2

3

4

5

6

7

8

9

public class JdkProxyFactory {

     public static Object getProxy(Object target){

         return Proxy.newProxyInstance(

                 target.getClass().getClassLoader(),

                 target.getClass().getInterfaces(),

                 new DebugInvocationHandler(target)

         );

     }

}

getProxy()  :主要通过 Proxy.newProxyInstance() 方法获取某个类的代理对象

5、实际使用

?

1

2

3

4

5

6

public static void main(String[] args) {

         //Rent rent = new Host();

         //Rent rentProxy= (Rent) Proxy.newProxyInstance(rent.getClass().getClassLoader(), rent.getClass().getInterfaces(),new DebugInvocationHandler(rent));

         Rent rentProxy = (Rent)JdkProxyFactory.getProxy( new Host());

         rentProxy.rent();

     }

运行上述代理的输出

before methodrent
房东要租房
after methodrent

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注的更多内容!    

原文链接:https://blog.csdn.net/ohwang/article/details/123312449

查看更多关于Java的动态代理和静态代理详解的详细内容...

  阅读:15次