概述

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

举例:明星(邓紫棋)<-----经纪人<------用户

     目标对象              代理对象

 

静态代理(一般不用)

  • 代理对象要实现与目标对象一样的接口
  • 可以做到在不修改目标对象的功能前提下,对目标对象功能进行扩展
  • 缺点
    • 因为代理对象,需要与目标对象实现一样的接口,所有会有很多代理类,
    • 一旦接口增加方法,目标对象与代理对象都要维护
 1 package cn.fuyi.a_static;
 2 
 3 public interface IUserDao {
 4     void save();
 5 }
 6 
 7 package cn.fuyi.a_static;
 8 
 9 public class UserDao implements IUserDao{
10 
11     public void save() {
12         System.out.println("=====已经保存数据====-");
13     }
14 }
15 
16 package cn.fuyi.a_static;
17 
18 public class UserProxy implements IUserDao{
19 
20     private IUserDao target;
21     public UserProxy(IUserDao target) {
22         this.target = target;
23     }
24     
25     @Override
26     public void save() {
27         System.out.println("开始事务");
28         target.save();
29         System.out.println("提交事务");
30     }
31 
32 }
33 
34 
35 package cn.fuyi.a_static;
36 
37 import static org.junit.Assert.*;
38 
39 import org.junit.Test;
40 
41 public class App {
42 
43     @Test
44     public void testStaticProxy() throws Exception {
45         //目标对象
46         IUserDao userDao = new UserDao();
47         
48         //代理对象
49         IUserDao userDaoProxy = new UserProxy(userDao);
50         
51         userDaoProxy.save();
52     }
53 }
54 
55 
56 /**Output
57    开启事务
58    =====已经保存数据====-
59    关闭事务
60  
61     
62 */
View Code

 

动态代理

  • 代理对象不需要实现接口
  • 目标对象一定要实现接口
  • 代理对象的生成是利用JDKAPI,动态的在内存中构建代理对象(需要我们指定目标对象实现的接口)
  • 也称JDK代理,接口代理
  • JDK中生成代理对象的API 

static Object newProxyInstance(

  ClassLoader loader,             指定当前目标对象使用的类加载器

   Class<?>[] interfaces,        目标对象实现的接口的类型

  InvocationHandler h)           事件处理器

 1 package cn.fuyi.b_dynamic;
 2 
 3 public interface IUserDao {
 4     void save();
 5 }
 6 
 7 package cn.fuyi.b_dynamic;
 8 
 9 public class UserDao implements IUserDao{
10 
11     public void save() {
12         System.out.println("=====已经保存数据====-");
13     }
14 }
15 
16 package cn.fuyi.b_dynamic;
17 
18 import java.lang.reflect.InvocationHandler;
19 import java.lang.reflect.Method;
20 import java.lang.reflect.Proxy;
21 
22 public class ProxyFactory {
23 
24     private Object target;
25     public ProxyFactory(Object target) {
26         this.target = target;
27     }
28     
29     public Object getProxyInstance() {
30         return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
31                 target.getClass().getInterfaces(), 
32                 new InvocationHandler() {
33                     
34                     @Override
35                     public Object invoke(Object proxy, Method method, Object[] args)
36                             throws Throwable {
37                         System.out.println("开启事务");
38                         
39                         //执行目标对象的方法
40                         Object returnValue = method.invoke(target, args);
41                             
42                         System.out.println("关闭事务");
43                         return returnValue;
44                     }
45                 });
46     }
47 }
48 
49 package cn.fuyi.b_dynamic;
50 
51 import static org.junit.Assert.*;
52 
53 import org.junit.Test;
54 
55 public class App {
56 
57     @Test
58     public void testDynamicProxy() throws Exception {
59         //目标对象
60         IUserDao target = new UserDao();
61         
62         //代理对象
63         IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
64         
65         proxy.save();
66     }
67 }
68 
69 /***
70    开启事务
71    =====已经保存数据====-
72    关闭事务
73  
74 */
View Code

 

Cglib代理

  • Cglib代理,也叫作子类代理,在内存中构建一个子类对象从而实现对目标对象功能的扩展
  • JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以用cglib实现
  • Cglib是一个强大的高性能的代码生成包,它可以在运行期间扩展Java类与实现Java接口,它广泛的被许多AOP的框架使用,如:spring AOP,为他们提供方法的interception(拦截);
  • Cglib包的底层通过使用一个小而快的字节码处理框架ASM,来装换字节码并生成新的类,不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉
  • spring-Core中包含了cglibg功能
  • 目标对象不能为final
  • 目标对象的方法如果为final/static,那么就不会别拦截,即不会执行目标对象额外的业务方法
  • 在spring的AOP编程中
    • 如果加入容器的目标对象有实现接口,就用JDK代理
    • 如果目标对象没有实现接口,就用Cglib代理
       1 package cn.fuyi.c_cglib;
       2 
       3 public class UserDao {
       4 
       5     public void save() {
       6         System.out.println("=====已经保存数据====-");
       7     }
       8 }
       9 
      10 package cn.fuyi.c_cglib;
      11 
      12 import java.lang.reflect.InvocationHandler;
      13 import java.lang.reflect.Method;
      14 import java.lang.reflect.Proxy;
      15 
      16 import org.springframework.cglib.proxy.Enhancer;
      17 import org.springframework.cglib.proxy.MethodInterceptor;
      18 import org.springframework.cglib.proxy.MethodProxy;
      19 
      20 public class ProxyFactory implements MethodInterceptor{
      21 
      22     private Object target;
      23     public ProxyFactory(Object target) {
      24         this.target = target;
      25     }
      26     
      27     public Object getProxyInstance() {
      28         //1.工具类
      29         Enhancer enhancer = new Enhancer();
      30         
      31         //2.设置父类,即目标对象
      32         enhancer.setSuperclass(target.getClass());
      33         
      34         //3.设置回调对象,即实现MethodInterceptor的类的对象
      35         enhancer.setCallback(this);
      36         
      37         //4.创建子类
      38         return enhancer.create();
      39     }
      40 
      41     @Override
      42     public Object intercept(Object obj, Method method, Object[] args,
      43             MethodProxy proxy) throws Throwable {
      44 
      45         System.out.println("开启事务");
      46         
      47         //执行目标对象的方法
      48         Object returnValue = method.invoke(target, args);
      49         
      50         System.out.println("提交事务");
      51         return returnValue;
      52     }
      53 }
      54 
      55 package cn.fuyi.c_cglib;
      56 
      57 import static org.junit.Assert.*;
      58 
      59 import org.junit.Test;
      60 
      61 public class App {
      62 
      63     @Test
      64     public void testDynamicProxy() throws Exception {
      65         //目标对象
      66         UserDao target = new UserDao();
      67         System.out.println(target.getClass());
      68         
      69         //代理对象
      70         UserDao proxy = (UserDao) new ProxyFactory(target).getProxyInstance();
      71         System.out.println(proxy.getClass());
      72         
      73         proxy.save();
      74     }
      75 }
      76 
      77 /***Output
      78 class cn.fuyi.c_cglib.UserDao
      79 class cn.fuyi.c_cglib.UserDao$$EnhancerByCGLIB$$b9ff5e0
      80 开启事务
      81 =====已经保存数据====-
      82 提交事务
      83 
      84 */
      View Code