java代理模式

1.代理模式

一句话解释:为其他对象提供一种代理以控制对这个对象的访问。

代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。

代理模式的功能主要是起到增强方法和权限拦截的作用。

举个例子,我想买房子,如果我自己一家一家去沟通谈论,未免太过浪费时间,同时,由于不了解房屋具体信息,如果我当面谈论发现对房屋不够满意,不想交易,这不仅耽误我的时间,也耽误屋主的时间。所以这个时候,我们需要房屋中介,也就是代理。现在我对某栋别墅特别感兴趣,由于这栋别墅价格昂贵,交易逻辑比较复杂,总之就是各种原因,导致该房屋在中介处只有一个人代理负责,该人也仅代理这一栋房屋,那么这就是静态代理,屋主给出的别墅的具体信息:567平米,每平米13670元,有三层等等。这是目标对象。代理给我介绍房屋具体信息,同时还向我提供其他信息:该别墅及其周围别墅近十年来成交金额变动,别墅周围环境以及贷款购买最便宜的方案等等,这是增强方法为了不耽误双方时间,代理需要对我的资金实力做一个考核,避免我是看着玩的,不买,这是权限拦截。所有代理给我的信息,包括目标对象,增强方法,权限拦截,这叫代理对象。现在由于资金周转不过来,我不想买这栋别墅了,我要买个普通二手房,并且不具体某一栋,只要达到我要求就可以了,这时候我要找一个可以负责多栋房屋出售的代理,这就是动态代理

 

2.基础类

接口(虚拟对象)

1 package demo01.service;
2 
3 public interface Animals {
4     void bark();
5 }

实现类(目标对象)

1 package demo01.service;
2 
3 public class AnimalsImpl implements Animals {
4     @Override
5     public void bark() {
6         System.out.println("汪汪汪");
7     }
8 }

测试类

 1 package demo01.controller;
 2 
 3 import demo01.dynamicProxy.DynamicProxyCglib;
 4 import demo01.dynamicProxy.DynamicProxyJdk;
 5 import demo01.service.Animals;
 6 import demo01.service.AnimalsImpl;
 7 import demo01.staticProxy.StaticProxy;
 8 
 9 public class Main {
10     public static void main(String args[]){
11 
12         Animals target = new AnimalsImpl();//真实对象
13 
14         /*静态代理*/
15         Animals staticProxy = new StaticProxy().bind(target);
16         staticProxy.bark();
17 
18         /*动态代理,idk*/
19         Animals dynamicProxyJdk = (Animals) new DynamicProxyJdk().bind(target);
20         dynamicProxyJdk.bark();
21 
22         /*动态代理,cglib*/
23         AnimalsImpl dynamicProxyCglib = (AnimalsImpl) new DynamicProxyCglib().bind(target);
24         dynamicProxyCglib.bark();
25     }
26 }

 

 

3.静态代理模式

静态代理在使用时,需要定义接口或者父类,目标对象与代理对象一起实现相同的接口或者是继承相同父类。

代理对象

 1 package demo01.staticProxy;
 2 
 3 import demo01.service.Animals;
 4 
 5 public class StaticProxy implements Animals {
 6 
 7     private Animals target = null;
 8 
 9     public Animals bind(Animals target){
10         this.target = target;
11         return target;
12     }
13 
14     @Override
15     public void bark() {
16         System.out.println("叫喊之前的动作。。。。。");
17         target.bark();
18         System.out.println("叫喊之后的动作。。。。。");
19     }
20 }

 

静态代理总结:

优点:可以做到在不修改目标对象的功能前提下,对目标功能扩展。

缺点

1.代理对象需要与目标对象实现一样的接口,会有很多代理类,类太多;

2.一旦接口增加方法,目标对象与代理对象都要维护。

4.动态代理模式

4.1 JDK代理

JDK动态代理在使用时,需要定义接口或者父类,目标对象需要实现接口或者是继承父类,代理对象不需要。

代理对象

 1 package demo01.dynamicProxy;
 2 
 3 import java.lang.reflect.InvocationHandler;
 4 import java.lang.reflect.Method;
 5 import java.lang.reflect.Proxy;
 6 
 7 /**
 8  * 代理类,实现InvocationHandler接口
 9  */
10 public class DynamicProxyJdk implements InvocationHandler {
11 
12     //存放目标对象的变量(被封装的对象是Object类型,接受任意类型的对象)
13     private Object target = null;
14 
15     /**
16      * 将目标对象传入,产生代理对象
17      * @param target 目标对象
18      * @return 代理对象
19      */
20     public Object bind(Object target){
21         this.target = target;
22         /*
23          * newProxyInstance方法用来产生一个代理对象
24          * 同时执行重写后的invoke方法来赋予该代理对象相应的动作行为
25          *
26          * newProxyInstance这个方法总共有3个参数
27          * 1.ClassLoader loader:指明生成代理对象使用哪个类装载器
28          * 2.Class<?>[] interfaces:通过接口指定,指明生成哪个对象的代理对象
29          * 3.InvocationHandler h:DynamicProxyJdk实现的InvocationHandler接口自身
30          */
31         Object proxy = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
32         return proxy;
33     }
34 
35     /**
36      * 重写invoke方法(这个方法不是我们显式的去调用)
37      * @param proxy 代理对象(没什么用)
38      * @param method 目标对象当前调用的方法
39      * @param args 方法参数
40      * @return
41      * @throws Throwable
42      */
43     @Override
44     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
45         System.out.println("叫喊之前的动作。。。。。");
46         Object result = method.invoke(target,args);
47         System.out.println("叫喊之后的动作。。。。。");
48         return result;
49     }
50 
51 }

 

JDK动态代理总结:
优点

1.代理对象,不需要实现接口;

2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象。

缺点:代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理,JDK代理要求被代理的类必须实现接口,有很强的局限性。

4.2 Cglib代理

Cglib动态代理在使用时,只需要定义一个具体类,目标对象和代理对象均部需要实现接口或者是继承父类。

代理对象

 1 package demo01.dynamicProxy;
 2 
 3 import demo01.service.AnimalsImpl;
 4 import net.sf.cglib.proxy.Enhancer;
 5 import net.sf.cglib.proxy.MethodInterceptor;
 6 import net.sf.cglib.proxy.MethodProxy;
 7 
 8 import java.lang.reflect.Method;
 9 
10 /**
11  * 代理类,实现MethodInterceptor接口
12  */
13 public class DynamicProxyCglib implements MethodInterceptor {
14 
15     //目标对象
16     private Object target = null;
17 
18     //给目标对象创建一个代理对象
19     public Object bind(Object target){
20         this.target = target;
21         //工具类
22         Enhancer enhancer = new Enhancer();
23         //设置父类
24         enhancer.setSuperclass(AnimalsImpl.class);
25         //设置回调函数
26         enhancer.setCallback(this);
27         //创建子类(代理对象)
28         return enhancer.create();
29     }
30 
31     /**
32      * 重写invoke方法(这个方法不是我们显式的去调用)
33      * @param obj 代理对象(没什么用)
34      * @param method 目标对象当前调用的方法
35      * @param args 方法参数
36      * @param proxy 代理对象当前调用的方法
37      * @return
38      * @throws Throwable
39      */
40     @Override
41     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
42         System.out.println("叫喊之前的动作。。。。。");
43         Object result = method.invoke(target,args);
44         System.out.println("叫喊之后的动作。。。。。");
45         return result;
46     }
47 }

 

pom.xml(Cglib需要导入jar)

1 <dependency>
2     <groupId>cglib</groupId>
3     <artifactId>cglib</artifactId>
4     <version>3.2.4</version>
5 </dependency>

Cglib动态代理总结:
优点

1.代理对象与目标对象均不需要实现接口;

2.执行效率比JDK动态代理高。

缺点:Cglib原理是针对目标类生成一个子类,覆盖其中的所有方法,所以目标类和方法不能声明为final类型。

posted @ 2019-03-15 17:19  天才在左  阅读(242)  评论(0)    收藏  举报