java代理(静态代理、动态代理)(JDK和cglib)

转自:http://blog.csdn.net/xiaohai0504/article/details/6832990


介绍       

代理模式 
        代理模式是常用的java设计模式,他的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。

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

        在JDK 1.3以后提供了动态代理的技术,允许开发者在运行期创建接口的代理实例。 JDK的动态代理主要涉及到java.lang.reflect包中的两个类:ProxyInvocationHandler。其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。

一)静态代理: 

1.Count.java

[java]  view plain copy
  1. <span style="font-size:16px;">package net.battier.dao;    
  2. /**   
  3.  * 定义一个账户接口   
  4.  *    
  5.  * @author Administrator   
  6.  *    
  7.  */     
  8. public interface Count {     
  9.     // 查看账户方法     
  10.     public void queryCount();     
  11.     // 修改账户方法     
  12.     public void updateCount();      
  13. }   </span>  
2.CountImpl.java

[java]  view plain copy
  1. package net.battier.dao.impl;     
  2. import net.battier.dao.Count;     
  3. /**   
  4.  * 委托类(包含业务逻辑)   
  5.  *    
  6.  * @author Administrator   
  7.  *    
  8.  */     
  9. public class CountImpl implements Count {  
  10.     @Override     
  11.     public void queryCount() {     
  12.         System.out.println("查看账户方法...");     
  13.     }     
  14.     @Override     
  15.     public void updateCount() {     
  16.         System.out.println("修改账户方法...");     
  17.     }     
  18. }     
3. CountProxy.java  

[java]  view plain copy
  1. package net.battier.dao.impl;     
  2.      
  3. import net.battier.dao.Count;     
  4.      
  5. /**   
  6.  * 这是一个代理类(增强CountImpl实现类)   
  7.  *    
  8.  * @author Administrator   
  9.  *    
  10.  */     
  11. public class CountProxy implements Count {     
  12.     private CountImpl countImpl;     
  13.      
  14.     /**   
  15.      * 覆盖默认构造器   
  16.      *    
  17.      * @param countImpl   
  18.      */     
  19.     public CountProxy(CountImpl countImpl) {     
  20.         this.countImpl = countImpl;     
  21.     }     
  22.      
  23.     @Override     
  24.     public void queryCount() {     
  25.         System.out.println("事务处理之前");     
  26.         // 调用委托类的方法;     
  27.         countImpl.queryCount();     
  28.         System.out.println("事务处理之后");     
  29.     }     
  30.      
  31.     @Override     
  32.     public void updateCount() {     
  33.         System.out.println("事务处理之前");     
  34.         // 调用委托类的方法;     
  35.         countImpl.updateCount();     
  36.         System.out.println("事务处理之后");     
  37.      
  38.     }     
  39.      
  40. }  

4.TestCount.java

[java]  view plain copy
  1. Java代码   
  2. package net.battier.test;     
  3. import net.battier.dao.impl.CountImpl;     
  4. import net.battier.dao.impl.CountProxy;     
  5. /**   
  6.  *测试Count类   
  7.  *    
  8.  * @author Administrator   
  9.  *    
  10.  */     
  11. public class TestCount {     
  12.     public static void main(String[] args) {     
  13.         CountImpl countImpl = new CountImpl();     
  14.         CountProxy countProxy = new CountProxy(countImpl);     
  15.         countProxy.updateCount();     
  16.         countProxy.queryCount();     
  17.     }     
  18. }    
       观察代码可以发现每一个代理类只能为一个接口服务,这样一来程序开发中必然会产生过多的代理,而且,所有的代理操作除了调用的方法不一样之外,其他的操作都一样,则此时肯定是重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。 

         总结:什么是静态代理,比如我想吃黄牛娃凉皮,但是不方便自己去买,就让我的司机顺便帮我买(这里司机就是代理类,买黄牛娃凉皮放到一个类中作为被代理类)

         类图如下:

    代理类和委托类(被代理类)都实现接口,代理类 聚合 委托类 ,再代理类中使用委托类调用委托类的方法。

==========================================================================

二)动态代理

1.定义一个接口和实现 

[java]  view plain copy
  1. <span style="font-weight: normal;"><span style="font-size:16px;">package com.tech.service;  
  2. public interface PersonService {  
  3.     public String getPersonName(Integer personId);  
  4.     public void save(String name);  
  5.     public void update(Integer personId, String name);  
  6. }  
  7.   
  8. package com.tech.service.impl;  
  9. import com.tech.service.PersonService;  
  10. public class PersonServiceBean implements PersonService {     
  11.     public String user = null;  
  12.   
  13.     public PersonServiceBean(){};  
  14.     public PersonServiceBean(String user){  
  15.         this.user = user;  
  16.     }  
  17.       
  18.     @Override  
  19.     public String getPersonName(Integer personId) {  
  20.         // TODO Auto-generated method stub  
  21.         System.out.println("这是find方法");  
  22.         return this.user;  
  23.     }  
  24.   
  25.     @Override  
  26.     public void save(String name) {  
  27.         // TODO Auto-generated method stub  
  28.         System.out.println("这是save方法");  
  29.     }  
  30.   
  31.     @Override  
  32.     public void update(Integer personId, String name) {  
  33.         // TODO Auto-generated method stub  
  34.         System.out.println("这是update方法");  
  35.     }  
  36.     public String getUser() {  
  37.         return user;  
  38.     }  
  39.     public void setUser(String user) {  
  40.         this.user = user;  
  41.     }  
  42.   
  43. }</span></span>  
2.JDK动态代理代理类

[java]  view plain copy
  1. package com.tech.jdkproxy;  
  2.   
  3. import java.lang.reflect.InvocationHandler;  
  4. import java.lang.reflect.Method;  
  5. import java.lang.reflect.Proxy;  
  6.   
  7. import com.tech.service.impl.PersonServiceBean;  
  8.   
  9. /** 
  10.  *   
  11.  * 切面   
  12.  * @author ch 
  13.  * 
  14.  */  
  15. public class JDKProxyFactory implements InvocationHandler{  
  16.   
  17.     private Object proxyObject; //目标对象  
  18.   
  19.     /** 
  20.      * 绑定委托对象并返回一个代理类  
  21.      * @param proxyObject 
  22.      * @return 
  23.      */  
  24.     public Object createProxyInstance(Object proxyObject) {  
  25.         this.proxyObject = proxyObject;  
  26.           
  27.         //生成代理类的字节码加载器   
  28.         ClassLoader classLoader = proxyObject.getClass().getClassLoader();  
  29.         //需要代理的接口,被代理类实现的多个接口都必须在这里定义  (这是一个缺陷,cglib弥补了这一缺陷)    
  30.         Class<?>[] proxyInterface = proxyObject.getClass().getInterfaces();//new Class[]{};   
  31.           
  32.         //织入器,织入代码并生成代理类     
  33.         return Proxy.newProxyInstance(classLoader,  
  34.                 proxyInterface, this);  
  35.   
  36.     }  
  37.   
  38.     @Override  
  39.     public Object invoke(Object proxy, Method method, Object[] args)  
  40.             throws Throwable {  
  41.         PersonServiceBean bean = (PersonServiceBean)this.proxyObject;  
  42.         Object result = null;  
  43.         //控制哪些用户执行切入逻辑  
  44.         if(bean.getUser() != null) {  
  45.             //执行原有逻辑     
  46.             result = method.invoke(this.proxyObject, args);  
  47.         }  
  48.         return result;  
  49.     }  
  50. }  
3.测试类

[java]  view plain copy
  1. package com.tech.junit;  
  2.   
  3. import org.junit.BeforeClass;  
  4. import org.junit.Test;  
  5.   
  6. import com.tech.jdkproxy.JDKProxyFactory;  
  7. import com.tech.service.PersonService;  
  8. import com.tech.service.impl.PersonServiceBean;  
  9.   
  10. public class PersonTest {  
  11.   
  12.     @BeforeClass  
  13.     public static void setUpBeforeClass() throws Exception {  
  14.     }  
  15.   
  16.     @Test  
  17.     public void Test() {  
  18.         JDKProxyFactory factory = new JDKProxyFactory();  
  19.         PersonService bean = (PersonService) factory  
  20.                 .createProxyInstance(new PersonServiceBean("lucy"));  
  21.         //用户为lucy,有权限  
  22.         bean.save("abc");  
  23.           
  24.         PersonService bean2 = (PersonService) factory  
  25.             .createProxyInstance(new PersonServiceBean());  
  26.         //用户为null,没有权限,不输出  
  27.         bean2.save("abc");  
  28.     }  
  29. }  

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值