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

来源:互联网 发布:扎古2.0知乎 编辑:程序博客网 时间:2024/04/30 20:24
今天,我们来看看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过程做了什么事。为了简单起见,为了便于关注问题点,我们用下面的测试代码:
Session session = sf.openSession();session.beginTransaction();UserVO user = null;user = (UserVO)session.load(UserVO.class, 2);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只有一个私有构造)
public HibernateProxy getProxy(Serializable id, SessionImplementor session) throws HibernateException {return JavassistLazyInitializer.getProxy(factory,entityName,persistentClass,interfaces,getIdentifierMethod,setIdentifierMethod,componentIdType,id,session,overridesEquals);}public static HibernateProxy getProxy(final Class factory, final String entityName, final Class persistentClass,final Class[] interfaces, final Method getIdentifierMethod,final Method setIdentifierMethod, final CompositeType componentIdType,final Serializable id, final SessionImplementor session,final boolean classOverridesEquals) throws HibernateException {final JavassistLazyInitializer instance = new JavassistLazyInitializer(entityName,persistentClass,interfaces, id,getIdentifierMethod,setIdentifierMethod,componentIdType,session,classOverridesEquals);final HibernateProxy proxy;try {proxy = ( HibernateProxy ) factory.newInstance();  // 创建代理对象}catch ( Exception e ) {throw new HibernateException("Javassist Enhancement failed: "+ persistentClass.getName(), e);}( ( ProxyObject ) proxy ).setHandler( instance );instance.constructed = true;return proxy;}

在创建代理对象的时候,有没有忽然发现有点不大对劲呢?那尼,factory已经存在?什么时候发生的事?这种觉得就是,在战争跟敌方大战好几场,忽然发现,打都是自己的感觉。那种感觉,让人瞬间就崩溃了。其它,前面已经说了,JavassistProxyFactory在Hibernate启动的时候就创建了。其实,创建之后,EntityPersister还对它进行了初始化(JavassistProxyFactory#postInstance(……);)这部分如下:
public void postInstantiate(final String entityName, final Set interfaces, final Method setIdentifierMethod, CompositeType componentIdType) throws HibernateException {this.entityName = entityName;this.persistentClass = persistentClass;this.interfaces = (Class[]) interfaces.toArray(NO_CLASSES);this.getIdentifierMethod = getIdentifierMethod;this.setIdentifierMethod = setIdentifierMethod;this.componentIdType = componentIdType;factory = JavassistLazyInitializer.getProxyFactory( persistentClass, this.interfaces );overridesEquals = ReflectHelper.overridesEquals(persistentClass);}public static Class getProxyFactory(Class persistentClass,Class[] interfaces) throws HibernateException {// note: interfaces is assumed to already contain HibernateProxy.classtry {ProxyFactory factory = new ProxyFactory();factory.setSuperclass( interfaces.length == 1 ? persistentClass : null );factory.setInterfaces( interfaces );factory.setFilter( FINALIZE_FILTER );return factory.createClass();} catch ( Throwable t ) {LOG.error(LOG.javassistEnhancementFailed(persistentClass.getName()), t);throw new HibernateException(LOG.javassistEnhancementFailed(persistentClass.getName()), t);}}

上面这两段代码告诉我们一件。先搞清楚一个关系,一个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。
public Object invoke(final Object proxy,final Method thisMethod, final Method proceed,final Object[] args) throws Throwable {if ( this.constructed ) {Object result;try {result = this.invoke( thisMethod, args, proxy );}catch ( Throwable t ) {throw new Exception( t.getCause() );}if ( result == INVOKE_IMPLEMENTATION ) {Object target = getImplementation();final Object returnValue;try {if ( ReflectHelper.isPublic( persistentClass, thisMethod ) ) {if ( !thisMethod.getDeclaringClass().isInstance( target ) ) {throw new ClassCastException( target.getClass().getName() );}returnValue = thisMethod.invoke( target, args );}else {if ( !thisMethod.isAccessible() ) {thisMethod.setAccessible( true );}returnValue = thisMethod.invoke( target, args );}if ( returnValue == target ) {if ( returnValue.getClass().isInstance(proxy) ) {return proxy;}else {LOG.narrowingProxy( returnValue.getClass() );}}return returnValue;}catch ( InvocationTargetException ite ) {throw ite.getTargetException();}}else {return result;}}else {// while constructor is runningif ( thisMethod.getName().equals( "getHibernateLazyInitializer" ) ) {return this;}else {return proceed.invoke( proxy, args );}}}


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




附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); // 这方法比较我把源码贴一下
public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType) throws HibernateException {final SessionImplementor source = event.getSession();EntityPersister persister;……final Class idClass = persister.getIdentifierType().getReturnedClass();if ( idClass != null && ! idClass.isInstance( event.getEntityId() ) ) {// we may have the kooky jpa requirement of allowing find-by-id where// "id" is the "simple pk value" of a dependent objects parent.  This// is part of its generally goofy "derived identity" "feature"……}final  EntityKey keyToLoad = source.generateEntityKey( event.getEntityId(), persister );try {if ( loadType.isNakedEntityReturned() ) {//do not return a proxy!//(this option indicates we are initializing a proxy)event.setResult( load(event, persister, keyToLoad, loadType) );}else {//return a proxy if appropriateif ( event.getLockMode() == LockMode.NONE ) {// 从这里进去event.setResult( proxyOrLoad(event, persister, keyToLoad, loadType) );}else {event.setResult( lockAndLoad(event, persister, keyToLoad, loadType, source) );}}}……}
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)我把它反编译之后内容如下:
package com.zframe.src.hibernate.pojo;import java.lang.reflect.Method;import javassist.util.proxy.MethodHandler;import javassist.util.proxy.ProxyObject;import javassist.util.proxy.RuntimeSupport;import org.hibernate.proxy.HibernateProxy;import org.hibernate.proxy.LazyInitializer;public class UserVO_$$_javassist_0 extends UserVO implements HibernateProxy,ProxyObject {private MethodHandler handler;public static byte[] _filter_signature;public static final long serialVersionUID;private static Method[] _methods_;public final Object _d0clone() throws CloneNotSupportedException {return super.clone();}protected final Object clone() throws CloneNotSupportedException {Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;RuntimeSupport.find2Methods(this, "clone", "_d0clone", 0,"()Ljava/lang/Object;", arrayOfMethod);return (Object) this.handler.invoke(this, arrayOfMethod[0],arrayOfMethod[1], new Object[0]);}public final boolean _d1equals(Object paramObject) {return super.equals(paramObject);}public final boolean equals(Object paramObject) {Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;RuntimeSupport.find2Methods(this, "equals", "_d1equals", 2,"(Ljava/lang/Object;)Z", arrayOfMethod);return ((Boolean) this.handler.invoke(this, arrayOfMethod[2],arrayOfMethod[3], new Object[] { paramObject })).booleanValue();}public final String _d3getAddress() {return super.getAddress();}public final String getAddress() {Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;RuntimeSupport.find2Methods(this, "getAddress", "_d3getAddress", 6,"()Ljava/lang/String;", arrayOfMethod);return (String) this.handler.invoke(this, arrayOfMethod[6],arrayOfMethod[7], new Object[0]);}public final LazyInitializer getHibernateLazyInitializer() {Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;RuntimeSupport.find2Methods(this, "getHibernateLazyInitializer", null,10, "()Lorg/hibernate/proxy/LazyInitializer;", arrayOfMethod);return (LazyInitializer) this.handler.invoke(this, arrayOfMethod[10],arrayOfMethod[11], new Object[0]);}public final int _d6getId() {return super.getId();}public final int getId() {Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;RuntimeSupport.find2Methods(this, "getId", "_d6getId", 12, "()I",arrayOfMethod);return ((Integer) this.handler.invoke(this, arrayOfMethod[12],arrayOfMethod[13], new Object[0])).intValue();}public final String _d7getName() {return super.getName();}public final String getName() {Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;RuntimeSupport.find2Methods(this, "getName", "_d7getName", 14,"()Ljava/lang/String;", arrayOfMethod);return (String) this.handler.invoke(this, arrayOfMethod[14],arrayOfMethod[15], new Object[0]);}public final int _d8hashCode() {return super.hashCode();}public final int hashCode() {Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;RuntimeSupport.find2Methods(this, "hashCode", "_d8hashCode", 16, "()I",arrayOfMethod);return ((Integer) this.handler.invoke(this, arrayOfMethod[16],arrayOfMethod[17], new Object[0])).intValue();}public final void _d11setAddress(String paramString) {super.setAddress(paramString);}public final void setAddress(String paramString) {Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;RuntimeSupport.find2Methods(this, "setAddress", "_d11setAddress", 22,"(Ljava/lang/String;)V", arrayOfMethod);this.handler.invoke(this, arrayOfMethod[22], arrayOfMethod[23],new Object[] { paramString });}public final void _d12setId(int paramInt) {super.setId(paramInt);}public final void setId(int paramInt) {Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;RuntimeSupport.find2Methods(this, "setId", "_d12setId", 24, "(I)V",arrayOfMethod);this.handler.invoke(this, arrayOfMethod[24], arrayOfMethod[25],new Object[] { new Integer(paramInt) });}public final void _d13setName(String paramString) {super.setName(paramString);}public final void setName(String paramString) {Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;RuntimeSupport.find2Methods(this, "setName", "_d13setName", 26,"(Ljava/lang/String;)V", arrayOfMethod);this.handler.invoke(this, arrayOfMethod[26], arrayOfMethod[27],new Object[] { paramString });}public final String _d14toString() {return super.toString();}public final String toString() {Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;RuntimeSupport.find2Methods(this, "toString", "_d14toString", 28,"()Ljava/lang/String;", arrayOfMethod);return (String) this.handler.invoke(this, arrayOfMethod[28],arrayOfMethod[29], new Object[0]);}public final Object writeReplace() {Method[] arrayOfMethod = jdField__methods__of_type_ArrayOfJavaLangReflectMethod;RuntimeSupport.find2Methods(this, "writeReplace", null, 36,"()Ljava/lang/Object;", arrayOfMethod);return (Object) this.handler.invoke(this, arrayOfMethod[36],arrayOfMethod[37], new Object[0]);}static {jdField__methods__of_type_ArrayOfJavaLangReflectMethod = new Method[38];serialVersionUID = -1L;}public void setHandler(MethodHandler paramMethodHandler) {this.handler = paramMethodHandler;}public MethodHandler getHandler() {return this.handler;}}