细说java动态代理和cglib的动态代理

  提到代理,想必大家对设计模式中的静态代理和动态代理都比较熟悉,小编之前在博客中对动态和静态代理进行了对比,这篇博文就只探讨java动态代理和cglib动态代理之间的区别;

♚  静态代理的温习

        在我们使用静态代理的时候,每一个代理类只能为一个接口提供服务,这这样一来在程序开发中会产生过多的代理,而且所有的代理操作除了调用的方法不一样之外,其他的操作都是相同的,这样就会造成过多的重复代码;

       为了解决上述问题,我们使用一个代理类来完成所有的代理功能,而这就需要引入动态代理;

♚  动态代理

       与静态代理相对的是动态代理,动态代理类的字节码在程序运行时由java反射机制动态生成,无需程序员手工编写它的源代码。动态代理不仅简化了编程工作,而且提高了软件系统的可扩展性,因为java反射机制可以生成任意类型的动态代理类。

      下面我们以一个示例来说明动态代理:该示例中以一个checkSecurity()的例子来演示动态代理:

UserManager.java:

[java] view plain copy
  1. <span style="font-size:18px;">package com.ysc.spring;  
  2.   
  3. /** 
  4.  * 要实现的接口 
  5.  * @author root 
  6.  * 
  7.  */  
  8. public interface UserManager {  
  9.       
  10.     public void addUser(String username,String password);  
  11.       
  12.     public void delUser(int userId);  
  13.       
  14.     public String findUserById(int userId);  
  15.       
  16.     public void modifyUser(int userId,String username,String passwordString);  
  17. }</span>  

UserManagerImpl.java

[java] view plain copy
  1. <span style="font-size:18px;">package com.ysc.spring;  
  2.   
  3. public class UserManagerImpl  implements UserManager {  
  4.   
  5.     @Override  
  6.     public void addUser(String username, String password) {  
  7.         //checkSecurity();  
  8.         System.out.println("-------------userManager.add()---------");  
  9.     }  
  10.   
  11.     @Override  
  12.     public void delUser(int userId) {  
  13.         //checkSecurity();  
  14.         System.out.println("-------------userManager.delUser()---------");  
  15.     }  
  16.           
  17.     @Override  
  18.     public String findUserById(int userId) {  
  19.         //checkSecurity();  
  20.         System.out.println("-------------userManager.findUserById()---------");  
  21.         return "张三";  
  22.     }  
  23.   
  24.     @Override  
  25.     public void modifyUser(int userId, String username, String passwordString) {  
  26.         //checkSecurity();  
  27.         System.out.println("-------------userManager.modifyUser()---------");  
  28.     }  
  29.       
  30. }</span>  

     由于检查安全性的方法是可以独立于当前接口中其他业务方法的,所以我们可以把这个独立的服务拿出来,放到一个代理类中,使用动态代理把检查安全性的方法动态的加入到每一个方法中,而这些代理的工作需要由一个单独的代理类来完成:

SecurityHandler.java:

[java] view plain copy
  1. <span style="font-size:18px;">package com.ysc.spring;  
  2.   
  3. import java.lang.reflect.InvocationHandler;  
  4. import java.lang.reflect.Method;  
  5. import java.lang.reflect.Proxy;  
  6.   
  7. public class SecurityHandler implements InvocationHandler {  
  8.   
  9.     private Object targetObject;  
  10.       
  11.     public Object createProxyInstanceObject(Object targetobObject){  
  12.         this.targetObject = targetobObject;  
  13.   
  14.         return Proxy.newProxyInstance(targetobObject.getClass().getClassLoader(),   
  15.                         targetobObject.getClass().getInterfaces(),  
  16.                         this);  
  17.           
  18.     }  
  19.       
  20.     @Override  
  21.     public Object invoke(Object proxy, Method method, Object[] args)  
  22.             throws Throwable {  
  23.         checkSecurity();  
  24.           
  25.         //调用目标方法  
  26.         Object ret = method.invoke(targetObject, args);  
  27.           
  28.         return ret;  
  29.     }  
  30.       
  31.     private void checkSecurity(){  
  32.         System.out.println("-----------checkSecurity----------");  
  33.     }  
  34.   
  35. }</span>  

     这样,我们就可以直接在客户端进行调用执行了:

Client.java:

[java] view plain copy
  1. <span style="font-size:18px;">package com.ysc.spring;  
  2.   
  3. /** 
  4.  *  
  5.  * 动态代理可以将系统中一些独立的服务(这些独立的服务具有横切性) 
  6.  * 而将这些独立的服务拿出来,使用动态代理就可以在运行时将服务自动加入到里头; 
  7.  * @author root 
  8.  * 
  9.  */  
  10. public class Client {  
  11.   
  12.     /** 
  13.      * @param args 
  14.      */  
  15.     public static void main(String[] args) {  
  16.         SecurityHandler handler = new SecurityHandler();  
  17.           
  18.         UserManager userManager = (UserManager)handler.createProxyInstanceObject(new UserManagerImpl());  
  19.           
  20.         userManager.addUser("zhangsan""123");  
  21.     }  
  22.   
  23. }</span>  

          通过上面的例子可以看出,通过动态代理我们实现了动态的将检查安全性切入到每一个方法中,但是动态代理依靠接口实现,那么这样的话就会导致一些没有接口的类,就不能通过jdk实现java的动态代理,而这个时候我们就需要转向cglib的动态代理:

♚  cglib动态代理

       cglib是针对类来实现代理的,它的原理是对指定的目标类生成一个类,并覆盖其中方法实现增强,看上述例子的cglib动态代理的实现:

       与动态代理不同,由于是针对类来实现,所以上述UserManagerImpl类不能直接在java代码中实现UserManager接口,所以我们需要一个配置文件来配置,且完成对哪些方法添加检查安全性的方法,ApplicationContext.xml 如下:

[java] view plain copy
  1. <span style="font-size:18px;"><?xml version="1.0" encoding="UTF-8"?>  
  2.   
  3. <beans xmlns="http://www.springframework.org/schema/beans"  
  4.     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"  
  5.     xmlns:context="http://www.springframework.org/schema/context"  
  6.     xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"  
  7.     xsi:schemaLocation="http://www.springframework.org/schema/beans   
  8.         http://www.springframework.org/schema/beans/spring-beans-3.2.xsd   
  9.         http://www.springframework.org/schema/mvc   
  10.         http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd   
  11.         http://www.springframework.org/schema/context   
  12.         http://www.springframework.org/schema/context/spring-context-3.2.xsd   
  13.         http://www.springframework.org/schema/aop   
  14.         http://www.springframework.org/schema/aop/spring-aop-3.2.xsd   
  15.         http://www.springframework.org/schema/tx   
  16.         http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">  
  17.       
  18.     <!-- 表示使用cglib代理 -->  
  19.     <aop:aspectj-autoproxy proxy-target-class="true"/>  
  20.        
  21.     <bean id="userManager" class="com.ysc.spring.UserManagerImpl"></bean>  
  22.     <bean id="securityHandler" class="com.ysc.spring.SecurityHandler"></bean>  
  23.       
  24.     <!-- 检查安全性的方法要附加在哪些方法上的配置 -->  
  25.     <aop:config>  
  26.         <aop:aspect id="securityAspect" ref="securityHandler">  
  27.             <aop:pointcut expression="execution(* add*(..))" id="addAddMethod"/>  
  28.             <aop:before method="checkSecurity" pointcut-ref="addAddMethod"/>  
  29.         </aop:aspect>  
  30.     </aop:config>  
  31. </beans></span>  
       动态代理中例子保持Client.java , Security.java , UserManager.java不变,只对UserManagerImpl.java 做出如下的修改:
[java] view plain copy
  1. <span style="font-size:18px;">package com.ysc.spring;  
  2.   
  3. public class UserManagerImpl  {  
  4. //implements UserManager {  
  5.   
  6.       
  7.     public void addUser(String username, String password) {  
  8.         //checkSecurity();  
  9.         System.out.println("-------------userManager.add()---------");  
  10.     }  
  11.   
  12.     public void delUser(int userId) {  
  13.         //checkSecurity();  
  14.         System.out.println("-------------userManager.delUser()---------");  
  15.     }  
  16.           
  17.     public String findUserById(int userId) {  
  18.         //checkSecurity();  
  19.         System.out.println("-------------userManager.findUserById()---------");  
  20.         return "张三";  
  21.     }  
  22.   
  23.     public void modifyUser(int userId, String username, String passwordString) {  
  24.         //checkSecurity();  
  25.         System.out.println("-------------userManager.modifyUser()---------");  
  26.     }  
  27.   
  28. }</span>  

 ✎   总结

 spring 默认使用的jdk的动态代理;

1.如果目标对象实现了接口,在默认情况下采用jdk的动态代理实现aop

2.如果目标对象实现了接口,也可以强制使用cglib生成代理实现aop

3.如果目标对象没有实现接口,那么必须引入cglib,spring会在jdk的动态代理和cglib代理之间切换

如何使用cglib强制生成代理;

* 加入cglib类库,cglib/*.jar

* 加入如下配置,表示强制使用cglib代理

<aop:aspectj-autoproxy proxy-target-class="true"/>

jdk动态代理和cglib代理的区别:

* jdk动态代理对实现了接口的类进行代理

* cglib代理可以对类代理,主要对指定的类生成一个子类,因为是继承,所以我们的目标最好不要使用使用final声明;

      到这里,jdk动态代理和cglib的动态代理之间的对比就已经结束了,希望能帮大家更深刻的理解静态代理、jdk动态代理和cglib动态代理。如果有更好的理解和建议,请留言哦!!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值