今天,我们来看看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 {
-
-
-
- try {
- 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 {
-
- if ( 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() ) ) {
-
-
-
- ……
- }
-
-
- final EntityKey keyToLoad = source.generateEntityKey( event.getEntityId(), persister );
- try {
- if ( loadType.isNakedEntityReturned() ) {
-
-
- event.setResult( load(event, persister, keyToLoad, loadType) );
- }
- else {
-
- if ( 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)我把它反编译之后内容如下:
这里注意:get方法,这个方法就是懒加载调用的方法
- 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;
- }
- }