java动态代理和spring动态代理对比

Java编译器编译好Java文件之后,产生.class 文件在磁盘中。这种class文件是二进制文件,内容是只有JVM虚拟机能够识别的机器码。JVM虚拟机读取字节码文件,取出二进制数据,加载到内存中,解析.class 文件内的信息,生成对应的 Class对象:

.java文件到jjvm的过程图:



 class字节码文件是根据JVM虚拟机规范中规定的字节码组织规则生成的、具体class文件是怎样组织类信息的,可以参考 此博文:深入理解Java Class文件格式系列。或者是Java虚拟机规范

在运行期的代码中生成二进制字节码

   由于JVM通过字节码的二进制信息加载类的,那么,如果我们在运行期系统中,遵循Java编译系统组织.class文件的格式和结构,生成相应的二进制数据,然后再把这个二进制数据加载转换成对应的类,这样,就完成了在代码中,动态创建一个类的能力了。


由于本人知识有限就不胡给大家介绍如何利用字节码增强,实现动态生成.clas文件了,大家可以参考http://www.blogjava.net/hello-yun/archive/2014/09/28/418365.html

今天就介绍如何利用jdk和cglib生成动态代理,:

首先我们编写目标类,即要被增强的类:

[html]  view plain  copy
  1. package com.leige.proxy;  
  2.   
  3. public class UserServiceImpl implements UserService {  
  4.   
  5.     @Override  
  6.     public void addUser() {  
  7.         // TODO Auto-generated method stub  
  8.         System.out.println("adddUser------");  
  9.     }  
  10.   
  11. }  

接口:

[html]  view plain  copy
  1. package com.leige.proxy;  
  2.   
  3. public interface UserService {  
  4.     public void addUser();  
  5.       
  6. }  
切面类即增强代码类利用动态代理可以动态的将增强代码加入目标类中:

[html]  view plain  copy
  1. package com.leige.proxy;  
  2.   
  3. public class MyAspect {  
  4.     public void before(){  
  5.         System.out.println("前置通知");  
  6.     }  
  7.     public void after(){  
  8.         System.out.println("后置通知");  
  9.     }  
  10. }  

工厂类:

[html]  view plain  copy
  1. package com.leige.proxy;  
  2.   
  3. import java.lang.reflect.InvocationHandler;  
  4. import java.lang.reflect.InvocationTargetException;  
  5. import java.lang.reflect.Method;  
  6. import java.lang.reflect.Proxy;  
  7.   
  8. import org.springframework.cglib.proxy.Callback;  
  9. import org.springframework.cglib.proxy.Enhancer;  
  10. import org.springframework.cglib.proxy.MethodInterceptor;  
  11. import org.springframework.cglib.proxy.MethodProxy;  
  12. import org.springframework.util.MethodInvoker;  
  13.   
  14. public class MyFactoryBean {  
  15.   
  16.     /**  
  17.      * @return  
  18.      * 利用jdk实现动态代理,  
  19.      * jdk实现动态代理,必须要保证目标类有接口,否则无法实现动态代理  
  20.      */  
  21.     public Object getBean(){  
  22.         //目标类,即被增强类  
  23.         UserService service=new UserServiceImpl();  
  24.         //切面类,即增强代码类  
  25.         MyAspect aspect=new MyAspect();  
  26.         //jdk动态代理实现  
  27.         return Proxy.newProxyInstance(this.getClass().getClassLoader(), service.getClass().getInterfaces(), new InvocationHandler() {  
  28.               
  29.             @Override  
  30.             public Object invoke(Object proxy, Method method, Object[] args)  
  31.                     throws Throwable {  
  32.                 // TODO Auto-generated method stub  
  33.                 //前置通知  
  34.                 aspect.before();  
  35.                 //执行目标类的方法:  
  36.                 Object obj=method.invoke(service, args);  
  37.                 //后置通知  
  38.                 aspect.after();  
  39.                 return obj;  
  40.             }  
  41.         });  
  42.           
  43.     }  
  44.       
  45.     /**  
  46.      * @return  
  47.      * 通过cglib实现动态代理,不需要目标类有接口,代理之后返回的是目标类的子类,所以目标类不是final的,  
  48.      *   
  49.      */  
  50.     public Object getBeanByCglib(){  
  51.         //目标类,即被增强类  
  52.         UserService service=new UserServiceImpl();  
  53.         //切面类,即增强代码类  
  54.         MyAspect aspect=new MyAspect();  
  55.         Enhancer enhancer=new Enhancer();  
  56.         //设置父类,即被代理类,cglib的代理对象通过子类实现的  
  57.         //因为我们的切入点是方法,所以使用MethodInterceptor  
  58.         enhancer.setSuperclass(service.getClass());  
  59.         enhancer.setCallback(new MethodInterceptor() {  
  60.               
  61.             @Override  
  62.             public Object intercept(Object proxy, Method method, Object[] args,  
  63.                     MethodProxy methodProxy) throws Throwable {  
  64.                 // TODO Auto-generated method stub  
  65.                 //前置通知  
  66.                 aspect.before();  
  67.                 //执行目标类的方法有两种方式  
  68.                 //Object obj=method.invoke(service, args);  
  69.                 /*执行的是代理对象的父类,在此代理对象是proxy,proxy的父类就是目标类即UserService  
  70.                  * 这是cglib的工作机制,即生成目标的的子类,作为代理对象  
  71.                  */  
  72.                 Object obj=methodProxy.invokeSuper(proxy, args);  
  73.                 //后置通知  
  74.                 aspect.after();  
  75.                 return obj;  
  76.             }  
  77.         });  
  78.         //创建代理类:  
  79.         Object obj=enhancer.create();  
  80.         return obj;  
  81.           
  82.           
  83.     }  
  84. }  

测试类:
[html]  view plain  copy
  1. package com.leige.proxy;  
  2.   
  3. import static org.junit.Assert.*;  
  4.   
  5. import org.junit.Test;  
  6. import org.junit.runner.RunWith;  
  7. import org.springframework.beans.factory.annotation.Autowired;  
  8. import org.springframework.test.context.ContextConfiguration;  
  9. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  
  10. @RunWith(SpringJUnit4ClassRunner.class)  
  11. @ContextConfiguration(locations="classpath:com/leige/proxy/beans.xml")  
  12. public class TestApp {  
  13.     @Autowired  
  14.     UserService userService;  
  15.     @Test  
  16.     public void test() {  
  17.         userService.addUser();  
  18.     }  
  19.   
  20. }  
beans.xml

[html]  view plain  copy
  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.        xsi:schemaLocation="http://www.springframework.org/schema/beans   
  6.                            http://www.springframework.org/schema/beans/spring-beans.xsd  
  7.                            http://www.springframework.org/schema/context  
  8.                            http://www.springframework.org/schema/context/spring-context.xsd">  
  9.                            <context:annotation-config/>  
  10.             <bean id="myfactory" class="com.leige.proxy.MyFactoryBean"/>  
  11.             <bean  id="userService" factory-bean="myfactory" factory-method="getBeanByCglib"/>  
  12.   
  13.   
  14. beans>  

以上是未使用springaop的动态代理,下面将介绍spring实现动态代理的方法:

第一种通知再切面类中配置,注意都是有接口的,这里不再写接口代码:

实现类:

[html]  view plain  copy
  1. package com.leige.aspect;  
  2.   
  3. public class StudentServiceImpl implements StudentService {  
  4.   
  5.     public void add() {  
  6.         System.out.println("addd student");  
  7.           
  8.     }  
  9.   
  10. }  

切面类,这种方法通知都是卸载代码中,xml中只需配置切面和切入点即可:
[html]  view plain  copy
  1. package com.leige.aspect;  
  2.   
  3. import org.aopalliance.intercept.MethodInterceptor;  
  4. import org.aopalliance.intercept.MethodInvocation;  
  5.   
  6. public class Myaspect implements MethodInterceptor {  
  7.   
  8.     public Object invoke(MethodInvocation mi) throws Throwable {  
  9.         // TODO Auto-generated method stub  
  10.         System.out.println("前置通知");  
  11.         Object obj=mi.proceed();  
  12.         System.out.println("后置通知");  
  13.         return obj;  
  14.     }  
  15.   
  16. }  

xml配置:

[html]  view plain  copy
  1. xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:aop="http://www.springframework.org/schema/aop"  
  4.        xmlns:context="http://www.springframework.org/schema/context"  
  5.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  6.        xsi:schemaLocation="http://www.springframework.org/schema/beans   
  7.                            http://www.springframework.org/schema/beans/spring-beans.xsd  
  8.                            http://www.springframework.org/schema/aop   
  9.                            http://www.springframework.org/schema/aop/spring-aop.xsd  
  10.                            http://www.springframework.org/schema/context  
  11.                            http://www.springframework.org/schema/context/spring-context.xsd  
  12.                            ">  
  13.                            
  14.                             
  15.     <bean id="studentServiceId" class="com.leige.aspect.StudentServiceImpl">bean>  
  16.       
  17.     <bean id="myAspect" class="com.leige.aspect.Myaspect">bean>  
  18.     <aop:config>  
  19.              
  20.     <bean id="personServiceId" class="com.leige.aspect2.PersonServiceImpl">bean>  
  21.       
  22.     <bean id="myAspect" class="com.leige.aspect2.MyAspect">bean>  
  23.             <aop:config>  
  24.           
  25.                 <aop:aspect ref="myAspect">  
  26.                   
  27.                 <aop:pointcut expression="execution(* com.leige.aspect2.PersonServiceImpl.*(..))" id="myPointCut"/>  
  28.                   
  29.                 

你可能感兴趣的:(java动态代理和spring动态代理对比)