Hibernate字节码增强

介绍

既然您已经了解了Hibernate脏检查的基础知识 ,我们就可以深入研究增强的脏检查机制。 虽然默认的图遍历算法对于大多数用例可能已经足够,但有时您需要优化的脏检查算法,并且检测方法比构建自己的自定义策略更方便。

使用AntHibernate工具

传统上,Hibernate Tools专注于Ant和Eclipse。 从Hibernate 3开始就可以使用字节码检测了,但是它需要Ant任务来运行CGLIBJavassist字节码增强例程。

Maven支持通过maven-antrun-plugin运行Ant任务:

<build>
	<plugins>
		<plugin>
			<artifactId>maven-antrun-plugin</artifactId>
			<executions>
				<execution>
					<id>Instrument domain classes</id>
					<configuration>
						<tasks>
							<taskdef name="instrument"
									 classname="org.hibernate.tool.instrument.javassist.InstrumentTask">
								<classpath>
									<path refid="maven.dependency.classpath"/>
									<path refid="maven.plugin.classpath"/>
								</classpath>
							</taskdef>
							<instrument verbose="true">
								<fileset dir="${project.build.outputDirectory}">
									<include name="**/flushing/*.class"/>
								</fileset>
							</instrument>
						</tasks>
					</configuration>
					<phase>process-classes</phase>
					<goals>
						<goal>run</goal>
					</goals>
				</execution>
			</executions>
			<dependencies>
				<dependency>
					<groupId>org.hibernate</groupId>
					<artifactId>hibernate-core</artifactId>
					<version>${hibernate.version}</version>
				</dependency>
				<dependency>
					<groupId>org.javassist</groupId>
					<artifactId>javassist</artifactId>
					<version>${javassist.version}</version>
				</dependency>
			</dependencies>
		</plugin>
	</plugins>
</build>

因此,对于以下实体源类:

@Entity
public class EnhancedOrderLine {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private Long number;

    private String orderedBy;

    private Date orderedOn;

    public Long getId() {
        return id;
    }

    public Long getNumber() {
        return number;
    }

    public void setNumber(Long number) {
        this.number = number;
    }

    public String getOrderedBy() {
        return orderedBy;
    }

    public void setOrderedBy(String orderedBy) {
        this.orderedBy = orderedBy;
    }

    public Date getOrderedOn() {
        return orderedOn;
    }

    public void setOrderedOn(Date orderedOn) {
        this.orderedOn = orderedOn;
    }
}

在构建期间,将生成以下类:

@Entity
public class EnhancedOrderLine implements FieldHandled {

  @Id
  @GeneratedValue(strategy=GenerationType.AUTO)
  private Long id;
  private Long number;
  private String orderedBy;
  private Date orderedOn;
  private transient FieldHandler $JAVASSIST_READ_WRITE_HANDLER;

  public Long getId() {
    return $javassist_read_id();
  }

  public Long getNumber() {
    return $javassist_read_number();
  }

  public void setNumber(Long number) {
    $javassist_write_number(number);
  }

  public String getOrderedBy() {
    return $javassist_read_orderedBy();
  }

  public void setOrderedBy(String orderedBy) {
    $javassist_write_orderedBy(orderedBy);
  }

  public Date getOrderedOn() {
    return $javassist_read_orderedOn();
  }

  public void setOrderedOn(Date orderedOn) {
    $javassist_write_orderedOn(orderedOn);
  }

  public FieldHandler getFieldHandler() {
    return this.$JAVASSIST_READ_WRITE_HANDLER;
  }

  public void setFieldHandler(FieldHandler paramFieldHandler) {
    this.$JAVASSIST_READ_WRITE_HANDLER = paramFieldHandler;
  }

  public Long $javassist_read_id() {
    if (getFieldHandler() == null)
      return this.id;
  }

  public void $javassist_write_id(Long paramLong) {
    if (getFieldHandler() == null) {
      this.id = paramLong;
      return;
    }
    this.id = ((Long)getFieldHandler().writeObject(this, "id", this.id, paramLong));
  }

  public Long $javassist_read_number() {
    if (getFieldHandler() == null)
      return this.number;
  }

  public void $javassist_write_number(Long paramLong) {
    if (getFieldHandler() == null) {
      this.number = paramLong;
      return;
    }
    this.number = ((Long)getFieldHandler().writeObject(this, "number", this.number, paramLong));
  }

  public String $javassist_read_orderedBy() {
    if (getFieldHandler() == null)
      return this.orderedBy;
  }

  public void $javassist_write_orderedBy(String paramString) {
    if (getFieldHandler() == null) {
      this.orderedBy = paramString;
      return;
    }
    this.orderedBy = ((String)getFieldHandler().writeObject(this, "orderedBy", this.orderedBy, paramString));
  }

  public Date $javassist_read_orderedOn() {
    if (getFieldHandler() == null)
      return this.orderedOn;
  }

  public void $javassist_write_orderedOn(Date paramDate) {
    if (getFieldHandler() == null) {
      this.orderedOn = paramDate;
      return;
    }
    this.orderedOn = ((Date)getFieldHandler().writeObject(this, "orderedOn", this.orderedOn, paramDate));
  }
}

尽管org.hibernate.bytecode.instrumentation.spi.AbstractFieldInterceptor设法拦截脏字段,但在进行脏污跟踪时从未真正询问过此信息。

InstrumentTask字节码增强功能只能分辨一个实体是否脏了,缺少对指示已修改哪些属性的支持,因此使InstrumentTask更适合“ No-proxy” LAZY提取策略

Hibernate增强Maven插件

Hibernate 4.2.8增加了对专用Maven字节码增强插件的支持

Maven字节码增强插件易于配置:

<build>
    <plugins>
        <plugin>
            <groupId>org.hibernate.orm.tooling</groupId>
            <artifactId>hibernate-enhance-maven-plugin</artifactId>
            <executions>
                 <execution>
                     <phase>compile</phase>
                     <goals>
                         <goal>enhance</goal>
                     </goals>
                 </execution>
             </executions>
        </plugin>
    </plugins>
</build>

在项目构建期间,将生成以下类:

@Entity
public class EnhancedOrderLine
        implements ManagedEntity, PersistentAttributeInterceptable, SelfDirtinessTracker {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private Long number;
    private String orderedBy;
    private Date orderedOn;

    @Transient
    private transient PersistentAttributeInterceptor $$_hibernate_attributeInterceptor;

    @Transient
    private transient Set $$_hibernate_tracker;

    @Transient
    private transient CollectionTracker $$_hibernate_collectionTracker;

    @Transient
    private transient EntityEntry $$_hibernate_entityEntryHolder;

    @Transient
    private transient ManagedEntity $$_hibernate_previousManagedEntity;

    @Transient
    private transient ManagedEntity $$_hibernate_nextManagedEntity;

    public Long getId() {
        return $$_hibernate_read_id();
    }

    public Long getNumber() {
        return $$_hibernate_read_number();
    }

    public void setNumber(Long number) {
        $$_hibernate_write_number(number);
    }

    public String getOrderedBy() {
        return $$_hibernate_read_orderedBy();
    }

    public void setOrderedBy(String orderedBy) {
        $$_hibernate_write_orderedBy(orderedBy);
    }

    public Date getOrderedOn() {
        return $$_hibernate_read_orderedOn();
    }

    public void setOrderedOn(Date orderedOn) {
        $$_hibernate_write_orderedOn(orderedOn);
    }

    public PersistentAttributeInterceptor $$_hibernate_getInterceptor() {
        return this.$$_hibernate_attributeInterceptor;
    }

    public void $$_hibernate_setInterceptor(PersistentAttributeInterceptor paramPersistentAttributeInterceptor) {
        this.$$_hibernate_attributeInterceptor = paramPersistentAttributeInterceptor;
    }

    public void $$_hibernate_trackChange(String paramString) {
        if (this.$$_hibernate_tracker == null)
            this.$$_hibernate_tracker = new HashSet();
        if (!this.$$_hibernate_tracker.contains(paramString))
            this.$$_hibernate_tracker.add(paramString);
    }

    private boolean $$_hibernate_areCollectionFieldsDirty() {
        return ($$_hibernate_getInterceptor() != null) && (this.$$_hibernate_collectionTracker != null);
    }

    private void $$_hibernate_getCollectionFieldDirtyNames(Set paramSet) {
        if (this.$$_hibernate_collectionTracker == null)
            return;
    }

    public boolean $$_hibernate_hasDirtyAttributes() {
        return ((this.$$_hibernate_tracker == null) || (this.$$_hibernate_tracker.isEmpty())) && ($$_hibernate_areCollectionFieldsDirty());
    }

    private void $$_hibernate_clearDirtyCollectionNames() {
        if (this.$$_hibernate_collectionTracker == null)
            this.$$_hibernate_collectionTracker = new CollectionTracker();
    }

    public void $$_hibernate_clearDirtyAttributes() {
        if (this.$$_hibernate_tracker != null)
            this.$$_hibernate_tracker.clear();
        $$_hibernate_clearDirtyCollectionNames();
    }

    public Set<String> $$_hibernate_getDirtyAttributes() {
        if (this.$$_hibernate_tracker == null)
            this.$$_hibernate_tracker = new HashSet();
        $$_hibernate_getCollectionFieldDirtyNames(this.$$_hibernate_tracker);
        return this.$$_hibernate_tracker;
    }

    private Long $$_hibernate_read_id() {
        if ($$_hibernate_getInterceptor() != null)
            this.id = ((Long) $$_hibernate_getInterceptor().readObject(this, "id", this.id));
        return this.id;
    }

    private void $$_hibernate_write_id(Long paramLong) {
        if (($$_hibernate_getInterceptor() == null) || ((this.id == null) || (this.id.equals(paramLong))))
            break label39;
        $$_hibernate_trackChange("id");
        label39:
        Long localLong = paramLong;
        if ($$_hibernate_getInterceptor() != null)
            localLong = (Long) $$_hibernate_getInterceptor().writeObject(this, "id", this.id, paramLong);
        this.id = localLong;
    }

    private Long $$_hibernate_read_number() {
        if ($$_hibernate_getInterceptor() != null)
            this.number = ((Long) $$_hibernate_getInterceptor().readObject(this, "number", this.number));
        return this.number;
    }

    private void $$_hibernate_write_number(Long paramLong) {
        if (($$_hibernate_getInterceptor() == null) || ((this.number == null) || (this.number.equals(paramLong))))
            break label39;
        $$_hibernate_trackChange("number");
        label39:
        Long localLong = paramLong;
        if ($$_hibernate_getInterceptor() != null)
            localLong = (Long) $$_hibernate_getInterceptor().writeObject(this, "number", this.number, paramLong);
        this.number = localLong;
    }

    private String $$_hibernate_read_orderedBy() {
        if ($$_hibernate_getInterceptor() != null)
            this.orderedBy = ((String) $$_hibernate_getInterceptor().readObject(this, "orderedBy", this.orderedBy));
        return this.orderedBy;
    }

    private void $$_hibernate_write_orderedBy(String paramString) {
        if (($$_hibernate_getInterceptor() == null) || ((this.orderedBy == null) || (this.orderedBy.equals(paramString))))
            break label39;
        $$_hibernate_trackChange("orderedBy");
        label39:
        String str = paramString;
        if ($$_hibernate_getInterceptor() != null)
            str = (String) $$_hibernate_getInterceptor().writeObject(this, "orderedBy", this.orderedBy, paramString);
        this.orderedBy = str;
    }

    private Date $$_hibernate_read_orderedOn() {
        if ($$_hibernate_getInterceptor() != null)
            this.orderedOn = ((Date) $$_hibernate_getInterceptor().readObject(this, "orderedOn", this.orderedOn));
        return this.orderedOn;
    }

    private void $$_hibernate_write_orderedOn(Date paramDate) {
        if (($$_hibernate_getInterceptor() == null) || ((this.orderedOn == null) || (this.orderedOn.equals(paramDate))))
            break label39;
        $$_hibernate_trackChange("orderedOn");
        label39:
        Date localDate = paramDate;
        if ($$_hibernate_getInterceptor() != null)
            localDate = (Date) $$_hibernate_getInterceptor().writeObject(this, "orderedOn", this.orderedOn, paramDate);
        this.orderedOn = localDate;
    }

    public Object $$_hibernate_getEntityInstance() {
        return this;
    }

    public EntityEntry $$_hibernate_getEntityEntry() {
        return this.$$_hibernate_entityEntryHolder;
    }

    public void $$_hibernate_setEntityEntry(EntityEntry paramEntityEntry) {
        this.$$_hibernate_entityEntryHolder = paramEntityEntry;
    }

    public ManagedEntity $$_hibernate_getPreviousManagedEntity() {
        return this.$$_hibernate_previousManagedEntity;
    }

    public void $$_hibernate_setPreviousManagedEntity(ManagedEntity paramManagedEntity) {
        this.$$_hibernate_previousManagedEntity = paramManagedEntity;
    }

    public ManagedEntity $$_hibernate_getNextManagedEntity() {
        return this.$$_hibernate_nextManagedEntity;
    }

    public void $$_hibernate_setNextManagedEntity(ManagedEntity paramManagedEntity) {
        this.$$_hibernate_nextManagedEntity = paramManagedEntity;
    }
}

很容易意识到,新的字节码增强逻辑与之前的InstrumentTask生成的逻辑不同。

自定义脏检查机制类似,新的字节码增强版本记录了已更改的属性,而不仅仅是简单的脏布尔标志。 更改时,增强逻辑会标记脏字段。 这种方法比必须将所有当前属性值与加载时快照数据进行比较要有效得多。

我们到了吗?

即使实体类字节码得到了增强,使用Hibernate 4.3.6 仍然以某种方式缺少一些拼图

例如,当调用setNumber(Long number)时 ,将执行以下拦截方法:

private void $$_hibernate_write_number(Long paramLong) {
        if (($$_hibernate_getInterceptor() == null) || ((this.number == null) || (this.number.equals(paramLong))))
            break label39;
        $$_hibernate_trackChange("number");
        label39:
        Long localLong = paramLong;
        if ($$_hibernate_getInterceptor() != null)
            localLong = (Long) $$_hibernate_getInterceptor().writeObject(this, "number", this.number, paramLong);
        this.number = localLong;
    }

在我的示例中,$$ _ hibernate_getInterceptor()始终为null,从而绕过$$ _ hibernate_trackChange(“ number”)调用。 因此,将不会记录任何脏属性,从而迫使Hibernate退回到默认的深度比较脏检查算法

因此,即使Hibernate在此特定领域取得了长足的进步,脏检查增强功能仍需要进行其他工作才能变得容易获得。

翻译自: https://www.javacodegeeks.com/2014/09/hibernate-bytecode-enhancement.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值