5.代理模式

【基本介绍】

  代理模式:为一个对象提供一个替身,以控制对这个对象的访问。即通过代理对象访问目标对象,这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。

  被代理的对象可以是远程对象,创建开销大的对象或者需要安全控制的对象。

  代理模式分类:静态代理、动态代理(JDK代理、接口代理)和Cglib代理(可以在内存动态的创建对象,而不需要实现接口,它属于动态代理的范畴)。

1.静态代理

  使用静态代理时,需要定义接口或者弗雷,被代理对象和代理对象一起实现同一接口或者继承同一父类

1 //接口
2 public interface ITeacherDao {
3     void teach(); // 授课的方法
4 }
同一接口
1 public class TeacherDao implements ITeacherDao {
2     @Override
3     public void teach() {
4         // TODO Auto-generated method stub
5         System.out.println(" 老师授课中  。。。。。");
6     }
7 }
被代理对象
 1 //代理对象,静态代理
 2 public class TeacherDaoProxy implements ITeacherDao{
 3     
 4     private ITeacherDao target; // 目标对象,通过接口来聚合
 5 
 6     //构造器
 7     public TeacherDaoProxy(ITeacherDao target) {
 8         this.target = target;
 9     }
10 
11     @Override
12     public void teach() {
13         // TODO Auto-generated method stub
14         System.out.println("开始代理  完成某些操作。。。。。 ");//方法
15         target.teach();
16         System.out.println("提交。。。。。");//方法
17     }
18 }
代理对象
 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         // TODO Auto-generated method stub
 5         //创建目标对象(被代理对象)
 6         TeacherDao teacherDao = new TeacherDao();
 7         
 8         //创建代理对象, 同时将被代理对象传递给代理对象
 9         TeacherDaoProxy teacherDaoProxy = new TeacherDaoProxy(teacherDao);
10         
11         //通过代理对象,调用到被代理对象的方法
12         //即:执行的是代理对象的方法,代理对象再去调用目标对象的方法 
13         teacherDaoProxy.teach();
14         /*
15         开始代理  完成某些操作。。。。。 
16          老师授课中  。。。。。
17         提交。。。。。
18          */
19     }
20 }
测试

  优点:在不修改目标对象的功能前提下,能通过代理对象对目标功能扩展

  缺点:因为代理对象要与目标对象实现一样的接口,所以会有很多代理类。一旦接口增加方法,目标对象和代理对象都需要维护。

2.动态代理

  代理对象不需要实现接口,但是目标对象需要实现接口。代理对象的生成也是利用JDK的API,动态地在内存中构建代理对象,所以动态代理也叫做JDK代理、接口代理。

  JDK中生成代理对象地API,代理类所在包:java.lang.reflect.Proxy,JDK使用newProxyInstance方法,需要三个参数,完整写法为

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

1 //接口
2 public interface ITeacherDao {
3 
4     void teach(); // 授课方法
5     void sayHello(String name);
6 }
接口
 1 public class TeacherDao implements ITeacherDao {
 2 
 3     @Override
 4     public void teach() {
 5         // TODO Auto-generated method stub
 6         System.out.println(" 老师授课中.... ");
 7     }
 8 
 9     @Override
10     public void sayHello(String name) {
11         // TODO Auto-generated method stub
12         System.out.println("hello " + name);
13     }
14     
15 }
被代理对象
 1 public class ProxyFactory {
 2 
 3     //维护一个目标对象 , Object
 4     private Object target;
 5 
 6     //构造器 , 对target 进行初始化
 7     public ProxyFactory(Object target) {
 8         
 9         this.target = target;
10     } 
11     
12     //给目标对象 生成一个代理对象
13     public Object getProxyInstance() {
14         //说明
15         /*
16          *  public static Object newProxyInstance(ClassLoader loader,
17                                           Class<?>[] interfaces,
18                                           InvocationHandler h)
19                                           
20             //1. ClassLoader loader : 指定当前目标对象使用的类加载器, 获取加载器的方法固定
21             //2. Class<?>[] interfaces: 目标对象实现的接口类型,使用泛型方法确认类型
22             //3. InvocationHandler h : 事情处理,执行目标对象的方法时,会触发事情处理器方法, 会把当前执行的目标对象方法作为参数传入
23          */
24         return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
25                 target.getClass().getInterfaces(), 
26                 new InvocationHandler() {
27                     
28                     @Override
29                     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
30                         // TODO Auto-generated method stub
31                         System.out.println("JDK代理开始~~");
32                         //反射机制调用目标对象的方法
33                         Object returnVal = method.invoke(target, args);
34                         System.out.println("JDK代理提交");
35                         return returnVal;
36                     }
37                 }); 
38     }
39 }
代理类
 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         // TODO Auto-generated method stub
 5         //创建目标对象
 6         ITeacherDao target = new TeacherDao();
 7         
 8         //给目标对象,创建代理对象, 可以转成 ITeacherDao
 9         ITeacherDao proxyInstance = (ITeacherDao)new ProxyFactory(target).getProxyInstance();
10     
11         // proxyInstance=class com.sun.proxy.$Proxy0 内存中动态生成了代理对象
12         System.out.println("proxyInstance=" + proxyInstance.getClass());
13         
14         //通过代理对象,调用目标对象的方法
15         //proxyInstance.teach();
16         
17         proxyInstance.sayHello(" tom ");
18         /*
19         proxyInstance=class com.sun.proxy.$Proxy0
20         JDK代理开始~~
21         hello  tom 
22         JDK代理提交
23          */
24     }
25 }
测试

3.Cglib代理

  静态代理和动态代理都要求被代理对象实现一个接口,但是有时被代理对象并没有实现接口,此时可以使用Cglib代理。

  Cglib代理也叫做子类代理,他是内存中都剪一个子类对象从而实现对目标对象地功能扩展。Cglib是一个功能强大的代码生成包,可以在运行期扩展Java类与实现Java接口,它广泛的被许多AOP框架使用,例如Spring AOP实现方法拦截。

  如果目标对象需要实现接口=》动态代理    如果目标对象不需要实现接口=》Cglib代理   

  如果目标对象地方法时final或者static,那么就不会被拦截,即不会执行目标对象额外的业务方法。

 【实现步骤】

①导包

②UML

 代理对象需要实现net.sf.cglib.proxy.MethodInterceptor接口

1 public class TeacherDao {
2 
3     public String teach() {
4         System.out.println(" 老师授课中  , 我是cglib代理,不需要实现接口 ");
5         return "hello";
6     }
7 }
被代理对象
 1 public class ProxyFactory implements MethodInterceptor {
 2 
 3     //维护一个目标对象
 4     private Object target;
 5     
 6     //构造器,传入一个被代理的对象
 7     public ProxyFactory(Object target) {
 8         this.target = target;
 9     }
10 
11     //返回一个代理对象:  是 target 对象的代理对象
12     public Object getProxyInstance() {
13         //1. 创建一个工具类
14         Enhancer enhancer = new Enhancer();
15         //2. 设置父类
16         enhancer.setSuperclass(target.getClass());
17         //3. 设置回调函数
18         enhancer.setCallback(this);
19         //4. 创建子类对象,即代理对象
20         return enhancer.create();
21         
22     }
23     
24     //重写  intercept 方法,会调用目标对象的方法
25     @Override
26     public Object intercept(Object arg0, Method method, Object[] args, MethodProxy arg3) throws Throwable {
27         // TODO Auto-generated method stub
28         System.out.println("Cglib代理模式 ~~ 开始");
29         Object returnVal = method.invoke(target, args);
30         System.out.println("Cglib代理模式 ~~ 提交");
31         return returnVal;
32     }
33 
34 }
代理对象
 1 public class Client {
 2 
 3     public static void main(String[] args) {
 4         // TODO Auto-generated method stub
 5         //创建目标对象
 6         TeacherDao target = new TeacherDao();
 7         //获取到代理对象,并且将目标对象传递给代理对象
 8         TeacherDao proxyInstance = (TeacherDao)new ProxyFactory(target).getProxyInstance();
 9 
10         //执行代理对象的方法,触发intecept 方法,从而实现 对目标对象的调用
11         String res = proxyInstance.teach();
12         System.out.println("res=" + res);
13         /*
14         Cglib代理模式 ~~ 开始
15         老师授课中  , 我是cglib代理,不需要实现接口
16         Cglib代理模式 ~~ 提交
17         res=hello
18          */
19     }
20 
21 }
测试
原文地址:https://www.cnblogs.com/qmillet/p/12112033.html