代理模式

什么是代理模式?

生活中的代理模式

房产中介,房东,韭菜;

房东想要出租房子,又没有好的途径,房东联系中介;

韭菜想要租房,但是不知道哪里有房源,于是找到了中介,中介带韭菜看房;

程序中的代理模式

servlet想通过调用Dao来完成某个功能,但三层架构的原则并不允许这样,

所以Servlet需要通过Service调用Dao来完成功能。

 

结合以上两种情况,总结出代理模式的作用有:

  • 控制访问:不让使用者直接访问目标,而是通过代理人来访问 (中不介让见房东

  • 功能增强 :在目标原功能上增加额外功能 (中介得收中介费

代理类需要做的事情:

  1. 目标类方法的调用

  2. 目标类功能的增强

代理类中一定要调用目标类中的方法

实现代理的方式:

  • 静态代理

  • 动态代理

静态代理的好处:

让目标类的行为更加纯粹,不用关注其他公共事务; 公共业务交给了代理角色,实现了业务的分工; 不会侵入目标类的代码,通过代理类附加公共业务(增强代码);

静态代理的缺点: 每个真实类都需要一个代理对象,虽然在不修改真实类源代码的情况下执行了很多其他代码, 但是这样会造成代码量翻倍,影响开发速度

 

 

动态代理

 

 

 

动态代理的实现方式

使用jdk的反射机制产生目标类的代理对象,无需再手写代理类,jdk提供的api直接帮你生成

使用JDK实现反射,需要Method,Proxy,IvocationHandler,这些类都为于java.lang.reflect包中;

如何使用Method类?

通过字节码对象调用GetMethod方法拿到该字节码对象中的某个方法对象。

Class.class.GetMethod(String MethodName,Class<?>... parameterTypes)

参数一:String MethodName

字节码对象中的方法名

参数二:形参类型的Class对象的一个数组。如果 parameterTypes 为 null,则按空数组处理。

注:参数二理解为要填入字节码对象就好了,类如一个方法的形参是String类型,就填入String.class

 

那么,问题来了,拿到这个方法对象后,该怎么运行呢?

public Object invoke(Object obj,                    
                    Object... args)
//列1:
Test test = new Test();
Method method = Test.class.getMethod("sayHello");
method.invoke(test,null);
//这三行代码的意思就是,执行Test类的无参SayHello方法
//第一步通过反射拿到Test中的sayHello方法对象method
//通过invoke放入Test的实现对象,形参来运行sayHello方法

 

如何使用InvocationHandler接口?

InvocationHandler接口里只有一个需要实现的方法

Object invoke(Object proxy,         //这个参数不用管ignore就好
             Method method, //这个参数是目标类的方法对象
             Object[] args) //这个参数是目标类方法的形参
             throws Throwable

这个方法的用途和静态代理类的用途一致,调用目标方法,执行功能增强;

这个方法的实现就是在方法体内写入增强代码和执行目标方法,如下

public class MyInvocation implements InvocationHandler {
   public MyInvocation(Hello impl){
       this.imple = impl;
  }
   public Hello imple = null;
   @Override
   public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
       System.out.println("前置通知");
       Object ret = method.invoke(imple,objects);//执行目标方法
       System.out.println("后置通知");
       return ret;
  }
}

现在写Invoke方法会对目标类所有的方法生效,只要执行方法,就会调用invoke,根据调用不同的方法名和参数JDK自动帮你生成参数。

相信很多小伙伴都会疑惑,这样只提供目标类和形参该怎么确认调用的方法呢?

因为InvocationHandler只是定好代理类该做的事情,还没有生成代理对象呢!

这个时候就需要用到Proxy这个类了!

 

Proxy类的使用

public static Object newProxyInstance(ClassLoader loader,    //目标类的类加载器
                                     Class<?>[] interfaces, //目标类的实现接口
                                     InvocationHandler h)  //代理类的定义
                              throws IllegalArgumentException
   

这个方法会为目标对象创建一个代理对象,代理对象内部有啥,由InvocationHandler实现类决定;

该方法返回的代理对象默认是Object类型,因为目标类实现了某个接口,可以向下转型接收。

public class MyProxy {
   public static void main(String[] args) {
       HelloImpl hello = new HelloImpl();
       InvocationHandler myInvocation = new MyInvocation(hello);
       Hello helloProxy = (Hello)Proxy.newProxyInstance(hello.getClass().getClassLoader(),
               hello.getClass().getInterfaces(), myInvocation);
       helloProxy.sayHello("你好");    
  }
}
//执行结果:
           //前置通知
           //你好
           //后置通知

 

总结:动态代理极大得降低了耦合,静态代理中,接口修改了内容,目标类和代理类都会收到牵连,但是动态代理就不会,受牵连的只有目标类

InvocationHandler---------------代理类需要干的事

Method-------------------------------目标类的方法

Proxy----------------------------------生成代理对象

 

 

 

 

posted @ 2022-04-05 21:07  MrPPP  阅读(76)  评论(0)    收藏  举报