hybris 有2个基础的Model
1.generation Model类,hybris Commerce Suite 编译时完成
2.Model 生命周期,在hybris Commerce Suite 运行时体现
在构建hybris系统时,构建框架为每个项目生成模型类和配置文件类型。Models的构建体现了所有的扩展,不论这个扩展是否扩能是否可用的在源码包或者二进制包中。Model构建过程中忽略了扩展
里extensioninfo.xml配置文件中generated属性 <coremodule>的值。
Model自动构建到bootstrap/gensrc位置
生成任何一种类型的Model,都遵循下面的规则:
1.model的名称为生成的类型加上Model后缀。比如,生成Product 的Model名称为ProductModel
2.还将为Model生成一个类似的包名:
字符串model 将最为包名的一部分被加到扩展的跟节点后面,而jalo 将被从包名中去除
例如:de.hybris.platform.europe1.jalo.TaxRow 对应的Model为 de.hybris.platform.europe1.model.TaxRowModel.
3.所有属性类型都是private的
4.会自动为所有的属性创建getter,setter方法
在hybris系统构建的过程中非常早期的时候Models就已经生成了。
Tip
更早的检查Data Model
Models 的创建都是依赖items.xml文件的,是匹配的。所以我们可以依赖
items.xml来检查创建的Model,这可以比在hmc中updating or initializing更早的发现问题。下面是个例子
<itemtype generate="true" code="ContactRequest" jaloclass="de.hybris.springmvcdemo.jalo.ContactRequest" extends="GenericItem" autocreate="true" > <attributes> <attribute qualifier="message" type="java.lang.String"> <persistence type="property"/> </attribute> </attributes> </itemtype>
在platform 的modelclasses
文件夹生成的Model 类如下:
package de.hybris.springmvcdemo.model; import de.hybris.platform.core.model.ItemModel; /** * Generated Model class for type ContactRequest first defined at extension *springmvcdemo* */ @SuppressWarnings("all") public class ContactRequestModel extends ItemModel { /** <i>Generated type code constant.</i>*/ public final static String _TYPECODE = "ContactRequest"; /** * <i>Generated constant</i> - Attribute key of <code>ContactRequest.message</code> attribute defined * at extension <code>springmvcdemo</code>. */ public static final String MESSAGE = "message"; /** <i>Generated variable</i> - Variable of <code>ContactRequest.message</code> attribute defined * at extension <code>springmvcdemo</code>. */ private String _message; /** * <i>Generated constructor</i> - for all mandatory attributes. * @deprecated Since 4.1.1 Please use the default constructor without parameters */ @Deprecated public ContactRequestModel() { super(); } /** * <i>Generated constructor</i> - for all mandatory and initial attributes. * @deprecated Since 4.1.1 Please use the default constructor without parameters * @param _owner initial attribute declared by type <code>Item</code> at extension <code>core</code> */ @Deprecated public ContactRequestModel(final ItemModel _owner) { super( _owner ); } /** * <i>Generated method</i> - Getter of the <code>ContactRequest.message</code> attribute defined * at extension <code>springmvcdemo</core>. * @return the message */ public String getMessage() { if( !isAttributeLoaded(MESSAGE)) { this._message = getAttributeProvider() == null ? null : (String) getAttributeProvider().getAttribute(MESSAGE); getValueHistory().loadOriginalValue(MESSAGE, this._message); } throwLoadingError(MESSAGE); return this._message; } /** * <i>Generated method</i> - Setter of <code>ContactRequest.message</code> attribute defined * at extension <code>springmvcdemo</code>. * * @param value the message */ public void setMessage(final String value) { this._message = value; markDirty(MESSAGE); } }
Models中的属性都是默认基于配置中的属性自动生成getter,setter方法。你可以在生成的过程中指定不需要哪个属性,或者执行所有的属性都不要那么就不会生成这个type对应的Model
排除所有的属性
<itemtype generate="true" code="ContactRequest" ... > <model generate="false"/> <attributes>...</attributes> </itemtype>
2.如果要排除某一个属性,你必须明确定义它。这样无论的数private 属性还是getter,setter方法都不会有这个属性。配置方法是在 items.xml这个属性里添加 <model generate="false" />。如下:
<attribute qualifier="message" type="java.lang.String"> <persistence type="property"/> <model generate="false"/></attribute>
生成的model构造函数如下:
/** * <i>Defined constructor from items.xml</i> * @param _message mandatory attribute declared by type <code>ContactRequest</code> at * extension <code>impex</code> */ public ContactRequestModel(final String _message) { super(); setMessage(_message); }
从4.2.2之后可以指定为属性生成的getter,setter方法
<attribute qualifier="message" type="java.lang.String"> <persistence type="property"/> <model> <getter name="myMessage"/> </model></attribute>
在Model中对应的生成的getter方法getMyMessage() 如下
public String getMessage() { ... } public String getMyMessage() { return this.getMessage(); }
此外,你还可以通过指定的getter,setter方法作为默认的getter,setter方法
<attribute qualifier="message" type="java.lang.String"> <persistence type="property"/> <model/> <getter name="myMessage" default="true"/> </model></attribute>
生成了getMyMessage 方法,而原来的getMessage 方法没有了
public String getMyMessage() { // now executes logic of former getMessage() method ... }
还有标记生成的getter,setter方法为过期的
<attribute qualifier="message" type="java.lang.String"> <persistence type="property"/> <model/> <getter name="myMessage" default="deprecated"/> </model></attribute>
生成的getMyMessage 方法被添加上了@deprecated 注解
public String getMessage() { ... } /** * @deprecated use {@link #getMessage()} instead */ @Deprecated public String getMyMessage() { return this.getMessage(); }
惰性加载是在实例化对象的时候不是立刻就设置对象的全部属性值。Model的加载原理就是惰性加载
一旦你加载一个Model,他包含所有的原始值。然而,在这种状态下,关系还未填写。一旦你通过调用相应的getter访问这样一种关系,这种关系是按需加载。这意味着一旦你加载一个模型,你需要担心加载任何依赖模型。
在hybris 5.0。当加载模型,Model value是不加载的。Model只是一个空的java实例,没有设置任何值。 All Model values are only loaded when any value of the Model is retrieved。这种机制在Model初始化时可以提高性能
如果要改变这种机制,在你的local.properties配置文件中设置 servicelayer.prefetch为 all or literal。literal 只会预加载原子属性的值,而不会加载引用的其他对象属性。
不建议设置all的加载机制,可能会出现循环依赖导致堆栈溢出错误。
因为按需加载模型的关系,在某些情况下避免调用getter和setter方法。观察下面这个简单的例子和2中方式。统计一个用户的总金额
在服务层根据用户的订单来累计总金额。使用User Model的getOrders() 方法可以迭代所有的订单,再来统计总金额。我们知道现在场景下数据量是很小的。
... public Double getTotal(UserModel user ) { double cumulativeTotalPrice = 0.0d; for (final OrderModel order : user.getOrders()) { cumulativeTotalPrice += order.getTotalPrice().doubleValue(); } } ...
但是,想想如果是订单数据量很大的场景呢。比如,B2B商城,可能一个厂商只用了一个用户。第一次调用getOrders()返回这个用户的所有的 相关订单,理想情况下,结果都会被缓存起来。但是糟糕的情况是,执行查询并返回成千上万的订单行。查询结果中的每一行,订单模型实例化,然后缓存。
另一种方式是在DAO层使用FlexibleSearch 查询。查询汇总每个订单的总价格为单个结果只有一行被从数据库获取:
public Double getTotal() { final FlexibleSearchQuery fq = new FlexibleSearchQuery("SELECT SUM(totalPrice) AS CUMULATIVE_PRICE FROM {Order} WHERE {user} = ?session.user"); fq.setResultClassList(Lists.newArrayList(Double.class)); final SearchResult<Double> search = fs.search(fq); final List<Double> result = search.getResult(); if (!result.isEmpty()) { return result.iterator().next(); } return Double.valueOf(0); }
一旦你加载一个模型或通过modelService创建它,就会放入Model 的上下文。Model context会跟踪Model 的所有变化,尤其是引用的新的还没有保存的Model
如果选择单独的保存Model,注意只有没有保存的Model会自动保存。已经创建的Model是不会保存的。
比如,你现在有一个CategoryModel对象,这个对象持有ProductModel对象,你修改了CategoryModel:
如果ProductModel是新建的还没有保存的,那么保存CategoryModel对象的时候同样会保存ProductModel。
这是因为ProductModel是一个新的对象,并且新的引用会保存
如果ProductModel已经保存过,再次保存CategoryModel的时候ProductModel不会再保存了
这是因为引用的对象ProductModel是已经存在的Model,存在的Model不会再次保存
因为Model context 会跟踪你的所有操作,可以保存所有的更改。你不需要单独保存每个模型。你可以一次保存所有的Model.关于怎么保存Model,请参考 Saving a Model 小节
如果你是用构造方法新建了一个Model,那么Model不会放入Model Context中。参见下面 Using a Constructor小节
你可以手工的为Model修改Model context
把一个Model加入context:
modelService.attach(model)
从context里删除一个Model:
modelService.detach(model)
Model context 绑定在HybrisRequestScope上,类似于标准的request作用域但是只作用于一个线程
当作用的session或者request呗关闭或者超时Model context会自动清除相关Model.所以可以判断,一个没有保存的Model被删除并不会影响线程的内存泄露
Model的创建或者修改储存在context中,如果你从数据库加载这样的模型,例如通过使用 flexible search,你得到同样的模型的实例存储在上下文。你必须意识到这种作坊是不能保证加载未修改的模型。如果你尝试展示2次在没有修改的前提下,你会得到 相同的对象,但是你不能依赖这个。最好的做法是在你的代码里持续保持对这个对象的引用。
记住Model context是线程本地的并且Model不是线程安全的。如果Model是多线程使用的情况需要对Model做同步处理。可以使用SessionService
最好不要使用事物回滚后的Model context。如果你要在事物回滚期间保存Models,可能会出错。这取决于你的使用模式。这是因为Model可能与他们的数据库表示处于不一致的状 态。比如要保存一个Model,他的主键已经生成但是因为回滚操作这个Model并没有被保存。因此不要使用事物回滚后的Model做检索或者创建