Java动态代理学习2——静态代理和动态代理

简介:

一、代理模式


代理模式是常用的java设计模式,特征是代理类委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。

代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。  

按照代理的创建时期,代理类可以分为两种:

静态代理:由程序员创建或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。 
动态代理:在程序运行时运用反射机制动态创建而成。

 

二、静态代理

 

 
  1. public interface CountDao  
  2. {  
  3.     // 查看账户方法  
  4.     public void queryCount();  
  5.  
  6.     // 修改账户方法  
  7.     public void updateCount();  
  8.  
  9. }  
  10.  
  11. public class CountDaoImpl implements CountDao  
  12. {  
  13.     public void queryCount()  
  14.     {  
  15.         System.out.println("查看账户方法...");  
  16.     }  
  17.  
  18.     public void updateCount()  
  19.     {  
  20.         System.out.println("修改账户方法...");  
  21.     }  
  22. }  
  23.  
  24. public class CountProxy implements CountDao  
  25. {  
  26.     private CountDao countDao;  
  27.  
  28.     public CountProxy(CountDao countDao)  
  29.     {  
  30.         this.countDao = countDao;  
  31.     }  
  32.  
  33.     @Override 
  34.     public void queryCount()  
  35.     {  
  36.         System.out.println("事务处理之前");  
  37.         countDao.queryCount();  
  38.         System.out.println("事务处理之后");  
  39.     }  
  40.  
  41.     @Override 
  42.     public void updateCount()  
  43.     {  
  44.         System.out.println("事务处理之前");  
  45.         countDao.updateCount();  
  46.         System.out.println("事务处理之后");  
  47.     }  
  48. }  
  49.  
  50. public class TestCount  
  51. {  
  52.     public static void main(String[] args)  
  53.     {  
  54.         CountProxy countProxy = new CountProxy(new CountDaoImpl());  
  55.         countProxy.updateCount();  
  56.         countProxy.queryCount();  
  57.     }  
  58. }  

观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且所有的代理操作除了调用的方法不一样之外其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。 


 

三、动态代理

与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。

 

1 JDK动态代理

JDK动态代理中包含一个类和一个接口

InvocationHandler接口

 

 
  1. public interface InvocationHandler {   
  2.     public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;   
  3. }   

Object proxy:指被代理的对象。 
Method method:要调用的方法 
Object[] args:方法调用时所需要的参数

可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject

 

Proxy类

Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:

 
  1. public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,   
  2. InvocationHandler h) throws IllegalArgumentException  

ClassLoader loader:类加载器 
Class<?>[] interfaces:得到全部的接口 
InvocationHandler h:得到InvocationHandler接口的子类实例

 
  1. public interface PersonService  
  2. {  
  3.     public void save();  
  4. }  
  5.  
  6. public class PersonServiceImpl implements PersonService  
  7. {  
  8.     public void save()  
  9.     {  
  10.         System.out.println("人员增加");  
  11.     }  
  12. }  
  13.  
  14. import java.lang.reflect.InvocationHandler;  
  15. import java.lang.reflect.Method;  
  16. import java.lang.reflect.Proxy;  
  17.  
  18. public class PersonProxy implements InvocationHandler  
  19. {  
  20.     // 目标对象  
  21.     private Object target;  
  22.  
  23.     // 返回一个代理类对象  
  24.     public Object createProxyInstance(Object target)  
  25.     {  
  26.         this.target = target;  
  27.         return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);  
  28.     }  
  29.  
  30.     // 上述代码中调用的this就是当前代理对象,会自动调用该方法  
  31.     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable  
  32.     {  
  33.         Object result = null;  
  34.         System.out.println("前置通知");  
  35.         try 
  36.         {     
  37.             result = method.invoke(target, args);  
  38.             System.out.println("后置通知");  
  39.         }  
  40.         catch(Exception e)  
  41.         {  
  42.             System.out.println("例外通知——出错啦");  
  43.         }  
  44.         finally 
  45.         {  
  46.             System.out.println("最终通知——结束啦");   
  47.         }  
  48.         return result;  
  49.     }  
  50. }  
  51.  
  52. public class TestProxy  
  53. {  
  54.     public static void main(String[] args)  
  55.     {  
  56.         PersonProxy bp = new PersonProxy();  
  57.         PersonService ps = (PersonService)bp.createProxyInstance(new PersonServiceImpl());  
  58.         ps.save();  
  59.     }  

前置通知
人员增加
后置通知
最终通知——结束啦

JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。 

 

2 CGLIB动态代理

JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承所以不能对final修饰的类进行代理。

 
  1. public interface PersonService  
  2. {  
  3.     public void save();  
  4. }  
  5.  
  6. public class PersonServiceImpl implements PersonService  
  7. {  
  8.     public void save()  
  9.     {  
  10.         System.out.println("人员增加");  
  11.     }  
  12. }  
  13.  
  14. import java.lang.reflect.InvocationHandler;  
  15. import java.lang.reflect.Method;  
  16. import java.lang.reflect.Proxy;  
  17.  
  18. /**  
  19.  * 使用CGLIB动态代理  
  20.  */ 
  21. public class PersonProxy implements MethodInterceptor  
  22. {  
  23.     private Object target;  
  24.  
  25.     // 返回一个代理类对象  
  26.     public Object createProxyInstance(Object target)  
  27.     {  
  28.         this.target = target;  
  29.         Enhancer enhancer = new Enhancer();  
  30.  
  31.         // 设置目标类为父类,会覆盖目标类的非final方法  
  32.         enhancer.setSuperclass(this.target.getClass());  
  33.  
  34.         // 回调方法  
  35.         enhancer.setCallback(this);  
  36.  
  37.         // 创建代理对象  
  38.         return enhancer.create();  
  39.     }  
  40.  
  41.     // 上述代码中调用的this就是当前代理对象,会自动调用该方法  
  42.     // 方法一  
  43.     @Override 
  44.     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable  
  45.     {  
  46.         Object result = null;  
  47.         System.out.println("前置通知");  
  48.         try 
  49.         { 
  50.             result = method.invoke(target, args);  
  51.             System.out.println("后置通知");  
  52.         }  
  53.         catch (Exception e)  
  54.         {  
  55.             System.out.println("例外通知——出错啦");  
  56.         }  
  57.         finally 
  58.         {  
  59.             System.out.println("最终通知——结束啦");  
  60.         }  
  61.         return result;  
  62.     }  
  63. }  
  64.  
  65. public class PersonProxy2 implements MethodInterceptor  
  66. {  
  67.     private Object target;  
  68.  
  69.     // 返回一个代理类对象  
  70.     public Object createProxyInstance(Object target)  
  71.     {  
  72.         this.target = target;  
  73.         Enhancer enhancer = new Enhancer();  
  74.  
  75.         // 设置目标类为父类,会覆盖目标类的非final方法  
  76.         enhancer.setSuperclass(this.target.getClass());  
  77.  
  78.         // 回调方法  
  79.         enhancer.setCallback(this);  
  80.  
  81.         // 创建代理对象  
  82.         return enhancer.create();  
  83.     }  
  84.       
  85.     // 方法二  
  86.     public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable  
  87.     {  
  88.         Object result = null;  
  89.         System.out.println("前置通知");  
  90.         try 
  91.         {   
  92.             result = proxy.invokeSuper(obj, args);  
  93.             System.out.println("后置通知");  
  94.         }  
  95.         catch (Exception e)  
  96.         {  
  97.             System.out.println("例外通知——出错啦");  
  98.         }  
  99.         finally 
  100.         {  
  101.             System.out.println("最终通知——结束啦");    
  102.         }  
  103.         return result;  
  104.     }  
  105. }  
  106.  
  107. public class TestProxy  
  108. {  
  109.     public static void main(String[] args)  
  110.     {  
  111.         PersonProxy cglib = new PersonProxy();  
  112.         PersonServiceClass ps1 = (PersonServiceClass) cglib.createProxyInstance(new PersonServiceClass());  
  113.         ps1.save();  
  114.         System.out.println("--------------------");  
  115.         PersonProxy2 cglib2 = new PersonProxy2();  
  116.         PersonServiceClass ps2 = (PersonServiceClass) cglib2.createProxyInstance(new PersonServiceClass());  
  117.         ps2.save();  
  118.     }  

前置通知
增加人员
后置通知
最终通知——结束啦
--------------------
前置通知
增加人员
后置通知
最终通知——结束啦

 

参考并演绎自地址:http://www.cnblogs.com/jqyp/archive/2010/08/20/1805041.html

本文转自IT徐胖子的专栏博客51CTO博客,原文链接http://blog.51cto.com/woshixy/1066208如需转载请自行联系原作者


woshixuye111

相关文章
|
2天前
|
Java Nacos 开发者
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
Java从入门到精通:4.2.1学习新技术与框架——以Spring Boot和Spring Cloud Alibaba为例
|
2天前
|
Dubbo Java 应用服务中间件
Java从入门到精通:3.2.2分布式与并发编程——了解分布式系统的基本概念,学习使用Dubbo、Spring Cloud等分布式框架
Java从入门到精通:3.2.2分布式与并发编程——了解分布式系统的基本概念,学习使用Dubbo、Spring Cloud等分布式框架
|
2天前
|
SQL Java 数据库连接
Java从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
ava从入门到精通:2.3.1数据库编程——学习JDBC技术,掌握Java与数据库的交互
|
2天前
|
设计模式 存储 前端开发
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
Java从入门到精通:2.2.1学习Java Web开发,了解Servlet和JSP技术,掌握MVC设计模式
|
2天前
|
Java API
Java从入门到精通:2.1.5深入学习Java核心技术之文件操作
Java从入门到精通:2.1.5深入学习Java核心技术之文件操作
|
2天前
|
并行计算 算法 安全
Java从入门到精通:2.1.3深入学习Java核心技术——掌握Java多线程编程
Java从入门到精通:2.1.3深入学习Java核心技术——掌握Java多线程编程
|
2天前
|
设计模式 Java 索引
由反射引出的Java动态代理与静态代理
由反射引出的Java动态代理与静态代理
12 0
|
7天前
|
存储 Java
Java动态转发代理IP的实现方法
Java动态转发代理IP的实现方法
23 11
|
7天前
|
JavaScript Java 测试技术
基于Java的驾考自主学习预约平台的设计与实现(源码+lw+部署文档+讲解等)
基于Java的驾考自主学习预约平台的设计与实现(源码+lw+部署文档+讲解等)
18 0
|
1月前
|
存储 安全 Java
24、使用 Java 官方教程学习:① 类变量和类方法详解;② 深入介绍 main() 方法
24、使用 Java 官方教程学习:① 类变量和类方法详解;② 深入介绍 main() 方法
38 1