Hibernate源码解析 Hibernate中的动态代理Javassist

今天,我们来看看Hibernate中的动态代理,对动态代理有兴趣的朋友可以读一读,看看Hibernate的作者们是怎么实现的,为我们之后用的时候提供一点思路。正如你所知Hibernate动态代理并不是用Java原生的方式,而是用了Javassist。Javassist可以直接操纵字节码,因此它用代理的效率会高一些。当然,还有其它框架。比如CGLib、BECL.但CGLib停止更新了很久了,据说Hibernate的作者曾尝试联系CGLib的作者,结果失败了。另外,Javassist也是JBOSS的一员。
在开始之前,说一句话:最近有点忙,有些日子没写博客了。主要是没几个人看,因此也不怎么想写了。

好的,现在正式开始。
大家都知道Hibernate中load一个对象跟get一个对象是有区别的。简单的说,load出来的是一个代理对象,而get出来是实实在在的POJO对象。也说是,load的过程做了延迟加载(Hibernate:lazy initializer proxy)。待用到这个对象的问题才去查询数据库,把记录放到对象中。在此,Hibernate不向数据库发SQL,这是load与get的区别。
今天的重点就是介绍load过程做了什么事。为了简单起见,为了便于关注问题点,我们用下面的测试代码:
[java]  view plain  copy
  1. Session session = sf.openSession();  
  2. session.beginTransaction();  
  3. UserVO user = null;  
  4. user = (UserVO)session.load(UserVO.class2);  
  5. session.getTransaction().commit();  
如果,你知道Hiberneate用Javassist的话,那你应该可以知道,今天的一切应该发生在org.hibernate.proxy.pojo.javassist这个包中。就算你不知道,它也是今天的主要战场。如果,你想用传统的方法找到这里,也是可以的,直接在session.load(UserVO.class, 2);在这个方法打个断点。然后一步一步的跟进去就可以了。大致流程请见文尾。
现在你只需要知道从这儿开始就可以了。
JavassistProxyFactory#getProxy(Serializable, SessionImplementor)

在这里有个事有必要提前说一下。
这里的JavassistProxyFactory这类是在Hibernate启动的时候创建的,由EntityPersister操刀创建的。一个POJO对应有一个EntityPersister,一个EntityPersister对应有一个ProxyFactory(JavassistProxyFactory)。想知道它什么时候创建,方法很简单,只需要在JavassistProxyFactory打个断点就可以了。

下面正式来看看Javassist在这一场战争中做了什么,战斗力如何。上面流程到这里,继续读下面的代码(JavassistLazyInitializer只有一个私有构造)
[java]  view plain  copy
  1. public HibernateProxy getProxy(Serializable id, SessionImplementor session) throws HibernateException {  
  2.     return JavassistLazyInitializer.getProxy(  
  3.             factory,  
  4.             entityName,  
  5.             persistentClass,  
  6.             interfaces,  
  7.             getIdentifierMethod,  
  8.             setIdentifierMethod,  
  9.             componentIdType,  
  10.             id,  
  11.             session,  
  12.             overridesEquals  
  13.     );  
  14. }  
  15.   
  16.   
  17. public static HibernateProxy getProxy(  
  18.         final Class factory, final String entityName, final Class persistentClass,  
  19.         final Class[] interfaces, final Method getIdentifierMethod,  
  20.         final Method setIdentifierMethod, final CompositeType componentIdType,  
  21.         final Serializable id, final SessionImplementor session,  
  22.         final boolean classOverridesEquals) throws HibernateException {  
  23.   
  24.   
  25.     final JavassistLazyInitializer instance = new JavassistLazyInitializer(  
  26.             entityName,  
  27.             persistentClass,  
  28.             interfaces, id,  
  29.             getIdentifierMethod,  
  30.             setIdentifierMethod,  
  31.             componentIdType,  
  32.             session,  
  33.             classOverridesEquals  
  34.     );  
  35.   
  36.   
  37.     final HibernateProxy proxy;  
  38.     try {  
  39.         proxy = ( HibernateProxy ) factory.newInstance();  // 创建代理对象  
  40.     }  
  41.     catch ( Exception e ) {  
  42.         throw new HibernateException(  
  43.                 "Javassist Enhancement failed: "  
  44.                 + persistentClass.getName(), e  
  45.         );  
  46.     }  
  47.     ( ( ProxyObject ) proxy ).setHandler( instance );  
  48.     instance.constructed = true;  
  49.     return proxy;  
  50. }  

在创建代理对象的时候,有没有忽然发现有点不大对劲呢?那尼,factory已经存在?什么时候发生的事?这种觉得就是,在战争跟敌方大战好几场,忽然发现,打都是自己的感觉。那种感觉,让人瞬间就崩溃了。其它,前面已经说了,JavassistProxyFactory在Hibernate启动的时候就创建了。其实,创建之后,EntityPersister还对它进行了初始化(JavassistProxyFactory#postInstance(……);)这部分如下:
[java]  view plain  copy
  1. public void postInstantiate(final String entityName,   
  2.         final Set interfaces, final Method setIdentifierMethod,   
  3.         CompositeType componentIdType) throws HibernateException {  
  4.   
  5.   
  6.     this.entityName = entityName;  
  7.     this.persistentClass = persistentClass;  
  8.     this.interfaces = (Class[]) interfaces.toArray(NO_CLASSES);  
  9.     this.getIdentifierMethod = getIdentifierMethod;  
  10.     this.setIdentifierMethod = setIdentifierMethod;  
  11.     this.componentIdType = componentIdType;  
  12.     factory = JavassistLazyInitializer.getProxyFactory( persistentClass, this.interfaces );  
  13.     overridesEquals = ReflectHelper.overridesEquals(persistentClass);  
  14. }  
  15.   
  16.   
  17. public static Class getProxyFactory(Class persistentClass,  
  18.             Class[] interfaces) throws HibernateException {  
  19.     // note: interfaces is assumed to already contain HibernateProxy.class  
  20.   
  21.   
  22.     try {  
  23.         ProxyFactory factory = new ProxyFactory();  
  24.         factory.setSuperclass( interfaces.length == 1 ? persistentClass : null );  
  25.         factory.setInterfaces( interfaces );  
  26.         factory.setFilter( FINALIZE_FILTER );  
  27.         return factory.createClass();  
  28.     } catch ( Throwable t ) {  
  29.         LOG.error(LOG.javassistEnhancementFailed(persistentClass.getName()), t);  
  30.         throw new HibernateException(LOG.javassistEnhancementFailed(persistentClass.getName()), t);  
  31.     }  
  32. }  

上面这两段代码告诉我们一件。先搞清楚一个关系,一个POJO(对Hibernate来说就是一个PersistentClass)有一个EntityPersister,一个EntityPersister只会创建一个ProxyFactory,建完之后存在EnttiyPersister中。因此,它就只初始化一次,结果就是ProxyFactory只被创建一次,也就是说每个都类都有自己的一个ProxyFactory(javassist.util.proxy.ProxyFactory)。这个对象用来生产Proxy对象,生产该POJO的代理对象。
这就是这两段合伙欺骗我们的内幕。

这ProxyFactory是这样的,它生产的每个都对象都继续它的POJO并实现HibernateProxy。从这里出去的只是一个半成品,它还会被JavassistProxyFactoryInitializer这个类加工。
注意一下,这个类实现了MethodHandler。还是MethodHandler这个接口来自javassist.util.proxy就说这么多吧,接下来你自己猜吧。

算了,我还是厚道点,直接说了吧。这个接口,跟java.lang.reflect.InvocationHandler 一个作用。即是在调用被代理对象时,会调一下这里面的invoke方法。(java se6 api中这么说的:在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。)
因此,它就可以当成(本来就是)MethodHandler的实现放入ProxyObject#setHandler()中,这一动作完成一个伟大的使命,它让这个ProxyFactory生产出来的对象成为了成品货了。

不难知道,之后它的代理对象的方法被调用时,都会调MethodHandler#invoke(……),这里的MethodHandler的具体实现为JavassistProxyFactoryInitializer。
[java]  view plain  copy
  1. public Object invoke(final Object proxy,  
  2.         final Method thisMethod, final Method proceed,  
  3.         final Object[] args) throws Throwable {  
  4.   
  5.   
  6.     if ( this.constructed ) {  
  7.         Object result;  
  8.         try {  
  9.             result = this.invoke( thisMethod, args, proxy );  
  10.         }  
  11.         catch ( Throwable t ) {  
  12.             throw new Exception( t.getCause() );  
  13.         }  
  14.         if ( result == INVOKE_IMPLEMENTATION ) {  
  15.             Object target = getImplementation();  
  16.             final Object returnValue;  
  17.             try {  
  18.                 if ( ReflectHelper.isPublic( persistentClass, thisMethod ) ) {  
  19.                     if ( !thisMethod.getDeclaringClass().isInstance( target ) ) {  
  20.                         throw new ClassCastException( target.getClass().getName() );  
  21.                     }  
  22.                     returnValue = thisMethod.invoke( target, args );  
  23.                 }  
  24.                 else {  
  25.                     if ( !thisMethod.isAccessible() ) {  
  26.                         thisMethod.setAccessible( true );  
  27.                     }  
  28.                     returnValue = thisMethod.invoke( target, args );  
  29.                 }  
  30.                   
  31.                 if ( returnValue == target ) {  
  32.                     if ( returnValue.getClass().isInstance(proxy) ) {  
  33.                         return proxy;  
  34.                     }  
  35.                     else {  
  36.                         LOG.narrowingProxy( returnValue.getClass() );  
  37.                     }  
  38.                 }  
  39.                 return returnValue;  
  40.             }  
  41.             catch ( InvocationTargetException ite ) {  
  42.                 throw ite.getTargetException();  
  43.             }  
  44.         }  
  45.         else {  
  46.             return result;  
  47.         }  
  48.     }  
  49.     else {  
  50.         // while constructor is running  
  51.         if ( thisMethod.getName().equals( "getHibernateLazyInitializer" ) ) {  
  52.             return this;  
  53.         }  
  54.         else {  
  55.             return proceed.invoke( proxy, args );  
  56.         }  
  57.     }  
  58. }  


正文结束了,不想总结了,因为困了。有问题请留言。




附1:流程
SessionImpl#load(Class, Serializable);
SessionImpl#byId(Class);
new IdentifierLoadAccessImpl(Class); // 这个过程有点绕,就是多调它的构造方法,3次。
IdentifierLoadAccessImpl(Class)#getReference(Serializable);
SessionImpl#fireLoad( Event, LoadEventListener.LOAD ); // 这是事件的注册,在《读Hibernate之二》里面详细讲过了。
DefaultLoadEventListener#onLoad(LoadEvent, LoadEventListener.LoadType); // 这方法比较我把源码贴一下
[java]  view plain  copy
  1. public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType) throws HibernateException {  
  2.     final SessionImplementor source = event.getSession();  
  3.     EntityPersister persister;  
  4.     ……  
  5.     final Class idClass = persister.getIdentifierType().getReturnedClass();  
  6.     if ( idClass != null && ! idClass.isInstance( event.getEntityId() ) ) {  
  7.         // we may have the kooky jpa requirement of allowing find-by-id where  
  8.         // "id" is the "simple pk value" of a dependent objects parent.  This  
  9.         // is part of its generally goofy "derived identity" "feature"  
  10.         ……  
  11.     }  
  12.   
  13.   
  14.     final  EntityKey keyToLoad = source.generateEntityKey( event.getEntityId(), persister );  
  15.     try {  
  16.         if ( loadType.isNakedEntityReturned() ) {  
  17.             //do not return a proxy!  
  18.             //(this option indicates we are initializing a proxy)  
  19.             event.setResult( load(event, persister, keyToLoad, loadType) );  
  20.         }  
  21.         else {  
  22.             //return a proxy if appropriate  
  23.             if ( event.getLockMode() == LockMode.NONE ) {  
  24.                 // 从这里进去  
  25.                 event.setResult( proxyOrLoad(event, persister, keyToLoad, loadType) );  
  26.             }  
  27.             else {  
  28.                 event.setResult( lockAndLoad(event, persister, keyToLoad, loadType, source) );  
  29.             }  
  30.         }  
  31.     }     
  32.     ……  
  33. }  
DefaultLoadEventListener#proxyOrLoad(LoadEvent, EntityPersister, EntityKey, LoadEventListener.LoadType)
//最后执行的是 
//if (options.isAllowProxyCreation()) {
// return createProxyIfNecessary(event, persister, keyToLoad, options, persistenceContext);
//}
DefaultLoadEventListener#createProxyIfNecessary();
AbstractEntityPersister#createProxy()
AbstractEntityTuplizer#createProxy();


附2:FactoryProxy#createClass()生成的class (UserVO_$$_javassist_0.class)我把它反编译之后内容如下:

这里注意:get方法,这个方法就是懒加载调用的方法

[java]  view plain  copy
  1. package com.zframe.src.hibernate.pojo;  
  2.   
  3.   
  4. import java.lang.reflect.Method;  
  5. import javassist.util.proxy.MethodHandler;  
  6. import javassist.util.proxy.ProxyObject;  
  7. import javassist.util.proxy.RuntimeSupport;  
  8. import org.hibernate.proxy.HibernateProxy;  
  9. import org.hibernate.proxy.LazyInitializer;  
  10.   
  11.   
  12. public class UserVO_$$_javassist_0 extends UserVO implements HibernateProxy,  
  13.         ProxyObject {  
  14.     private MethodHandler handler;  
  15.     public static byte[] _filter_signature;  
  16.     public static final long serialVersionUID;  
  17.     private static Method[] _methods_;  
  18.   
  19.   
  20.     public final Object _d0clone() throws CloneNotSupportedException {  
  21.         return super.clone();  
  22.     }  
  23.   
  24.   
  25.     protected final Object clone() throws CloneNotSupportedException {  
  26.         Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;  
  27.         RuntimeSupport.find2Methods(this"clone""_d0clone"0,  
  28.                 "()Ljava/lang/Object;", arrayOfMethod);  
  29.         return (Object) this.handler.invoke(this, arrayOfMethod[0],  
  30.                 arrayOfMethod[1], new Object[0]);  
  31.     }  
  32.   
  33.   
  34.     public final boolean _d1equals(Object paramObject) {  
  35.         return super.equals(paramObject);  
  36.     }  
  37.   
  38.   
  39.     public final boolean equals(Object paramObject) {  
  40.         Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;  
  41.         RuntimeSupport.find2Methods(this"equals""_d1equals"2,  
  42.                 "(Ljava/lang/Object;)Z", arrayOfMethod);  
  43.         return ((Boolean) this.handler.invoke(this, arrayOfMethod[2],  
  44.                 arrayOfMethod[3], new Object[] { paramObject })).booleanValue();  
  45.     }  
  46.   
  47.   
  48.     public final String _d3getAddress() {  
  49.         return super.getAddress();  
  50.     }  
  51.   
  52.   
  53.     public final String getAddress() {  
  54.         Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;  
  55.         RuntimeSupport.find2Methods(this"getAddress""_d3getAddress"6,  
  56.                 "()Ljava/lang/String;", arrayOfMethod);  
  57.         return (String) this.handler.invoke(this, arrayOfMethod[6],  
  58.                 arrayOfMethod[7], new Object[0]);  
  59.     }  
  60.   
  61.   
  62.     public final LazyInitializer getHibernateLazyInitializer() {  
  63.         Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;  
  64.         RuntimeSupport.find2Methods(this"getHibernateLazyInitializer"null,  
  65.                 10"()Lorg/hibernate/proxy/LazyInitializer;", arrayOfMethod);  
  66.         return (LazyInitializer) this.handler.invoke(this, arrayOfMethod[10],  
  67.                 arrayOfMethod[11], new Object[0]);  
  68.     }  
  69.   
  70.   
  71.     public final int _d6getId() {  
  72.         return super.getId();  
  73.     }  
  74.   
  75.   
  76.     public final int getId() {  
  77.         Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;  
  78.         RuntimeSupport.find2Methods(this"getId""_d6getId"12"()I",  
  79.                 arrayOfMethod);  
  80.         return ((Integer) this.handler.invoke(this, arrayOfMethod[12],  
  81.                 arrayOfMethod[13], new Object[0])).intValue();  
  82.     }  
  83.   
  84.   
  85.     public final String _d7getName() {  
  86.         return super.getName();  
  87.     }  
  88.   
  89.   
  90.     public final String getName() {  
  91.         Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;  
  92.         RuntimeSupport.find2Methods(this"getName""_d7getName"14,  
  93.                 "()Ljava/lang/String;", arrayOfMethod);  
  94.         return (String) this.handler.invoke(this, arrayOfMethod[14],  
  95.                 arrayOfMethod[15], new Object[0]);  
  96.     }  
  97.   
  98.   
  99.     public final int _d8hashCode() {  
  100.         return super.hashCode();  
  101.     }  
  102.   
  103.   
  104.     public final int hashCode() {  
  105.         Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;  
  106.         RuntimeSupport.find2Methods(this"hashCode""_d8hashCode"16"()I",  
  107.                 arrayOfMethod);  
  108.         return ((Integer) this.handler.invoke(this, arrayOfMethod[16],  
  109.                 arrayOfMethod[17], new Object[0])).intValue();  
  110.     }  
  111.   
  112.   
  113.     public final void _d11setAddress(String paramString) {  
  114.         super.setAddress(paramString);  
  115.     }  
  116.   
  117.   
  118.     public final void setAddress(String paramString) {  
  119.         Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;  
  120.         RuntimeSupport.find2Methods(this"setAddress""_d11setAddress"22,  
  121.                 "(Ljava/lang/String;)V", arrayOfMethod);  
  122.         this.handler.invoke(this, arrayOfMethod[22], arrayOfMethod[23],  
  123.                 new Object[] { paramString });  
  124.     }  
  125.   
  126.   
  127.     public final void _d12setId(int paramInt) {  
  128.         super.setId(paramInt);  
  129.     }  
  130.   
  131.   
  132.     public final void setId(int paramInt) {  
  133.         Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;  
  134.         RuntimeSupport.find2Methods(this"setId""_d12setId"24"(I)V",  
  135.                 arrayOfMethod);  
  136.         this.handler.invoke(this, arrayOfMethod[24], arrayOfMethod[25],  
  137.                 new Object[] { new Integer(paramInt) });  
  138.     }  
  139.   
  140.   
  141.     public final void _d13setName(String paramString) {  
  142.         super.setName(paramString);  
  143.     }  
  144.   
  145.   
  146.     public final void setName(String paramString) {  
  147.         Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;  
  148.         RuntimeSupport.find2Methods(this"setName""_d13setName"26,  
  149.                 "(Ljava/lang/String;)V", arrayOfMethod);  
  150.         this.handler.invoke(this, arrayOfMethod[26], arrayOfMethod[27],  
  151.                 new Object[] { paramString });  
  152.     }  
  153.   
  154.   
  155.     public final String _d14toString() {  
  156.         return super.toString();  
  157.     }  
  158.   
  159.   
  160.     public final String toString() {  
  161.         Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;  
  162.         RuntimeSupport.find2Methods(this"toString""_d14toString"28,  
  163.                 "()Ljava/lang/String;", arrayOfMethod);  
  164.         return (String) this.handler.invoke(this, arrayOfMethod[28],  
  165.                 arrayOfMethod[29], new Object[0]);  
  166.     }  
  167.   
  168.   
  169.     public final Object writeReplace() {  
  170.         Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;  
  171.         RuntimeSupport.find2Methods(this"writeReplace"null36,  
  172.                 "()Ljava/lang/Object;", arrayOfMethod);  
  173.         return (Object) this.handler.invoke(this, arrayOfMethod[36],  
  174.                 arrayOfMethod[37], new Object[0]);  
  175.     }  
  176.   
  177.   
  178.     static {  
  179.         jdField__methods__of_type_ArrayOfJavaLangReflectMethod = new Method[38];  
  180.         serialVersionUID = -1L;  
  181.     }  
  182.   
  183.   
  184.     public void setHandler(MethodHandler paramMethodHandler) {  
  185.         this.handler = paramMethodHandler;  
  186.     }  
  187.   
  188.   
  189.     public MethodHandler getHandler() {  
  190.         return this.handler;  
  191.     }  
  192. }  
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值