Hibernate字节码增强
介紹
既然您已經(jīng)了解了Hibernate臟檢查的基礎(chǔ)知識(shí) ,我們就可以深入研究增強(qiáng)的臟檢查機(jī)制。 雖然默認(rèn)的圖遍歷算法對(duì)于大多數(shù)用例可能已經(jīng)足夠,但有時(shí)您需要優(yōu)化的臟檢查算法,并且檢測(cè)方法比構(gòu)建自己的自定義策略更方便。
使用AntHibernate工具
傳統(tǒng)上,Hibernate Tools專注于Ant和Eclipse。 從Hibernate 3開始就可以使用字節(jié)碼檢測(cè)了,但是它需要Ant任務(wù)來運(yùn)行CGLIB或Javassist字節(jié)碼增強(qiáng)例程。
Maven支持通過maven-antrun-plugin運(yùn)行Ant任務(wù):
<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>因此,對(duì)于以下實(shí)體源類:
@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;} }在構(gòu)建期間,將生成以下類:
@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設(shè)法攔截臟字段,但在進(jìn)行臟污跟蹤時(shí)從未真正詢問過此信息。
InstrumentTask字節(jié)碼增強(qiáng)功能只能分辨一個(gè)實(shí)體是否臟了,缺少對(duì)指示已修改哪些屬性的支持,因此使InstrumentTask更適合“ No-proxy” LAZY提取策略 。
Hibernate增強(qiáng)Maven插件
Hibernate 4.2.8增加了對(duì)專用Maven字節(jié)碼增強(qiáng)插件的支持 。
Maven字節(jié)碼增強(qiáng)插件易于配置:
<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>在項(xiàng)目構(gòu)建期間,將生成以下類:
@Entity public class EnhancedOrderLineimplements ManagedEntity, PersistentAttributeInterceptable, SelfDirtinessTracker {@Id@GeneratedValue(strategy = GenerationType.AUTO)private Long id;private Long number;private String orderedBy;private Date orderedOn;@Transientprivate transient PersistentAttributeInterceptor $$_hibernate_attributeInterceptor;@Transientprivate transient Set $$_hibernate_tracker;@Transientprivate transient CollectionTracker $$_hibernate_collectionTracker;@Transientprivate transient EntityEntry $$_hibernate_entityEntryHolder;@Transientprivate transient ManagedEntity $$_hibernate_previousManagedEntity;@Transientprivate 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;} }很容易意識(shí)到,新的字節(jié)碼增強(qiáng)邏輯與之前的InstrumentTask生成的邏輯不同。
與自定義臟檢查機(jī)制類似,新的字節(jié)碼增強(qiáng)版本記錄了已更改的屬性,而不僅僅是簡(jiǎn)單的臟布爾標(biāo)志。 更改時(shí),增強(qiáng)邏輯會(huì)標(biāo)記臟字段。 這種方法比必須將所有當(dāng)前屬性值與加載時(shí)快照數(shù)據(jù)進(jìn)行比較要有效得多。
我們到了嗎?
即使實(shí)體類字節(jié)碼得到了增強(qiáng),使用Hibernate 4.3.6 仍然以某種方式缺少一些拼圖 。
例如,當(dāng)調(diào)用setNumber(Long number)時(shí) ,將執(zhí)行以下攔截方法:
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”)調(diào)用。 因此,將不會(huì)記錄任何臟屬性,從而迫使Hibernate退回到默認(rèn)的深度比較臟檢查算法 。
因此,即使Hibernate在此特定領(lǐng)域取得了長足的進(jìn)步,臟檢查增強(qiáng)功能仍需要進(jìn)行其他工作才能變得容易獲得。
- 代碼可在GitHub上獲得 。
翻譯自: https://www.javacodegeeks.com/2014/09/hibernate-bytecode-enhancement.html
總結(jié)
以上是生活随笔為你收集整理的Hibernate字节码增强的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 正确的喷香水方法 如何正确喷香水
- 下一篇: Mockito匹配器优先