码迷,mamicode.com
首页 > 其他好文 > 详细

实现动态代理的两种方式介绍+例子demo(JDK、CGlib)

时间:2014-08-26 17:21:16      阅读:389      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   http   color   os   java   使用   io   

JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类如何实现动态代理呢

这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。


一、JDK这种方式动态代理

1. 没引入spring配置文件时,怎么实现JDK动态代理


情景介绍:如何解决全站中文乱码问题?

我们会定义一个过滤器:CharacterEncodingFilter

  1. package cn.xym.empmis.web.filter; 
  2.  
  3. import java.io.IOException; 
  4. import java.lang.reflect.InvocationHandler; 
  5. import java.lang.reflect.Method; 
  6. import java.lang.reflect.Proxy; 
  7.  
  8. import javax.servlet.Filter; 
  9. import javax.servlet.FilterChain; 
  10. import javax.servlet.FilterConfig; 
  11. import javax.servlet.ServletException; 
  12. import javax.servlet.ServletRequest; 
  13. import javax.servlet.ServletResponse; 
  14. import javax.servlet.http.HttpServletRequest; 
  15. import javax.servlet.http.HttpServletResponse; 
  16.  
  17. /**
  18. * 解决全站乱码问题
  19. * @author Administrator
  20. *
  21. */ 
  22. public class CharacterEncodingFilter implements Filter{ 
  23.  
  24.     @Override 
  25.     public void init(FilterConfig filterconfig) throws ServletException { 
  26.         // TODO Auto-generated method stub 
  27.          
  28.     } 
  29.  
  30.     @Override 
  31.     public void doFilter(ServletRequest servletrequest, 
  32.             ServletResponse servletresponse, FilterChain filterchain) 
  33.             throws IOException, ServletException { 
  34.          
  35.          
  36.         final HttpServletRequest request = (HttpServletRequest) servletrequest; 
  37.         HttpServletResponse response = (HttpServletResponse) servletresponse; 
  38.         request.setCharacterEncoding("UTF-8");  //只能解决Post方式提交的乱码问题,无法解决get提交的乱码 
  39.          
  40.         //可以用包装设计模式,也可以用动态代理技术来解决get请求的乱码问题 
  41.          
  42.         filterchain.doFilter((ServletRequest) Proxy.newProxyInstance(CharacterEncodingFilter.class.getClassLoader() 
  43.                 , request.getClass().getInterfaces() 
  44.                 , new InvocationHandler() { 
  45.                      
  46.                     @Override 
  47.                     public Object invoke(Object proxy, Method method, Object[] args) 
  48.                             throws Throwable { 
  49.                         //proxy表示:动态代理对象 
  50.                         //method表示:需要代理的方法 
  51.                         //args表示需要代理方法的参数 
  52.                         if (!method.getName().equals("getParameter")){ 
  53.                             return method.invoke(request, args); 
  54.                         } 
  55.                         if (!request.getMethod().equalsIgnoreCase("get")){ 
  56.                             return method.invoke(request, args); 
  57.                         } 
  58.                         //满足要拦截处理的条件了 
  59.                         String value = (String) method.invoke(request,args); 
  60.                         if (value == null){ 
  61.                             return null
  62.                         } 
  63.                         return new String(value.getBytes("iso8859-1"),"UTF-8"); 
  64.                     } 
  65.                 }), response); 
  66.     } 
  67.     @Override 
  68.     public void destroy() { 
  69.         // TODO Auto-generated method stub 
  70.          
  71.     } 
  72.      


2.引入spring配置文件时,实现JDK动态代理功能

要设计出几种需要的“通知类型”的类,在配置文件中配置代理对象,指定代理目标(即要被代理的对象),指定所有要代理的接口(列表),最后把需要的“通知类型”织入到代理对象!

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <beans xmlns="http://www.springframework.org/schema/beans" 
  3.         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  4.         xmlns:context="http://www.springframework.org/schema/context" 
  5.         xmlns:tx="http://www.springframework.org/schema/tx" 
  6.         xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd 
  7.                 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd 
  8.                 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> 
  9.          
  10.         <!-- 准备要做为目标对象(被代理对象) --> 
  11.         <bean id="userServiceImpl" class="cn.cubic.aop.service.impl.UserServiceImpl" /> 
  12.      
  13.         <!-- 配置通知对象 --> 
  14.         <!-- 前置通知 --> 
  15.         <bean id="myMethodBeforeAdvice" class="cn.cubic.aop.MyMethodBeforeAdvice"/> 
  16.         <!-- 后置通知 --> 
  17.         <bean id="myAfterReturningAdvice" class="cn.cubic.aop.MyAfterReturningAdvice" /> 
  18.         <!-- 环绕通知 --> 
  19.         <bean id="myMethodInterceptor" class="cn.cubic.aop.MyMethodInterceptor" /> 
  20.         <!-- 异常通知 --> 
  21.         <bean id="myThrowsAdvice" class="cn.cubic.aop.MyThrowsAdvice"/> 
  22.          
  23.         <!-- 引入通知 ,自定义切入点,了解即可--> 
  24.         <bean id="myMethodBeforeAdviceFilter" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor"> 
  25.             <property name="advice" ref="myMethodBeforeAdvice"/> 
  26.             <property name="mappedNames"> 
  27.                 <list> 
  28.                     <value>sayHello</value> 
  29.                 </list> 
  30.             </property> 
  31.         </bean> 
  32.          
  33.          
  34.         <!-- 配置代理对象 --> 
  35.         <bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean"> 
  36.              
  37.             <!-- 指定你希望代理的目标对象 --> 
  38.             <property name="target" ref="userServiceImpl" /> 
  39.              
  40.             <!-- 指定“代理接口”的列表 --> 
  41.             <property name="proxyInterfaces"> 
  42.                 <list> 
  43.                     <value>cn.cubic.aop.service.IAbstractService</value> 
  44.                     <value>cn.cubic.aop.service.IAbstractService2</value> 
  45.                 </list> 
  46.             </property> 
  47.              
  48.             <!-- 把“通知”织入代理对象 --> 
  49.             <property name="interceptorNames"> 
  50.                 <list> 
  51.                     <value>myMethodBeforeAdviceFilter</value> 
  52.                     <value>myAfterReturningAdvice</value> 
  53.                     <value>myMethodInterceptor</value> 
  54.                     <value>myThrowsAdvice</value> 
  55.                 </list> 
  56.             </property> 
  57.         </bean> 
  58.          
  59. </beans> 



二、CGlib 这种方式实现动态代理

CGLIBProxy类:

  1. package cn.cubic.aop.cglib; 
  2.  
  3. import java.lang.reflect.Method; 
  4.  
  5. import net.sf.cglib.proxy.Enhancer; 
  6. import net.sf.cglib.proxy.MethodInterceptor; 
  7. import net.sf.cglib.proxy.MethodProxy; 
  8.  
  9.  
  10. /**
  11. *  
  12. * Simple to Introduction 
  13. *
  14. * @ProjectName:  [springAop]
  15. * @Package:      [cn.cubic.aop.cglib] 
  16. * @ClassName:    [CGLIBProxy]  
  17. * @Description:  [描述该类的功能]  
  18. * @Author:       [逍遥梦]  
  19. * @CreateDate:   [2014-3-1 下午4:47:22]  
  20. * @UpdateUser:   [逍遥梦]  
  21. * @UpdateDate:   [2014-3-1 下午4:47:22]  
  22. * @UpdateRemark: [说明本次修改内容] 
  23. * @Version:      [v1.0]
  24. *
  25. */ 
  26. public class CGLIBProxy implements MethodInterceptor{ 
  27.      
  28.      private Enhancer enhancer = new Enhancer(); 
  29.      
  30.      public Object getProxy(Class clazz){ 
  31.            
  32.           //设置父类 
  33.           enhancer.setSuperclass(clazz); 
  34.           enhancer.setCallback(this); 
  35.            
  36.           //通过字节码技术动态创建子类实例 
  37.           return enhancer.create(); 
  38.      } 
  39.      
  40.     /**
  41.      * 所有的方法都会被这个方法所拦截。该类实现了创建子类的方法与代理的方法。getProxy(SuperClass.class)方法通过入参即父类的字节码,通过扩展父类的class来创建代理对象。intercept()方法拦截所有目标类方法的调用,obj表示目标类的实例,method为目标类方法的反射对象,args为方法的动态入参,proxy为代理类实例。
  42.      */ 
  43.     @Override 
  44.     public Object intercept(Object obj, Method method, Object[] args, 
  45.             MethodProxy methodproxy) throws Throwable { 
  46.          
  47.         System.out.println("cglib实现的前置代理"); 
  48.          
  49.         //通过代理类调用父类中的方法 
  50.         Object result = methodproxy.invokeSuper(obj, args); 
  51.          
  52.         System.out.println("cglib实现的后置代理"); 
  53.         return result; 
  54.     } 
  55.  
  56.      


CGLIBUserServiceImpl类:

  1. package cn.cubic.aop.service.impl; 
  2.  
  3. public class CGLIBUserServiceImpl { 
  4.      
  5.     public void sayHello(){ 
  6.         System.out.println("CGLIBUserServiceImpl的sayHello方法被调用!"); 
  7.     } 
  8.      
  9.     public void sayBye(){ 
  10.         System.out.println("CGLIBUserServiceImpl的sayHello方法被调用!"); 
  11.     } 

Main函数:

  1. package cn.cubic.aop.junit; 
  2.  
  3. import cn.cubic.aop.cglib.CGLIBProxy; 
  4. import cn.cubic.aop.service.impl.CGLIBUserServiceImpl; 
  5.  
  6. public class CGLIBTest { 
  7.  
  8.     /**
  9.      * @param args
  10.      */ 
  11.     public static void main(String[] args) { 
  12.  
  13.         CGLIBProxy proxy = new CGLIBProxy(); 
  14.          
  15.         //生成子类,创建代理类 
  16.         CGLIBUserServiceImpl impl = (CGLIBUserServiceImpl)proxy.getProxy(CGLIBUserServiceImpl.class); 
  17.         impl.sayHello(); 
  18.          
  19.     } 
  20.  


三、比较两种方式的优缺点

CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理!

实现动态代理的两种方式介绍+例子demo(JDK、CGlib)

标签:des   style   blog   http   color   os   java   使用   io   

原文地址:http://blog.csdn.net/luo446718254/article/details/38850279

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!