gpt4 book ai didi

java - Spring 和 Hibernate 混搭,是 @Entity 的代理对象,并添加了额外的 @Service

转载 作者:行者123 更新时间:2023-12-01 17:46:39 25 4
gpt4 key购买 nike

我认为这可能是我知道答案但只是不喜欢的情况。

我的出发点是之前的一个问题, Hibernate @Entity conflict with Spring @Autowired for non-column object .

我有一个@Entity,它“自然”地与另一组实体以一对多关系链接。在我的示例中,我将其称为 ItemEntity,并且它具有(非常)大的价格历史记录。如此之大,Hibernate 延迟加载会成为性能 killer ,因为真正的用例永远不需要所有历史记录(数十万的价格,而不是通常需要的几百)。因此,我有一个 PriceCache 服务,可以按需获取我需要的内容。

从正常用例来看,“自然”的事情是检索感兴趣的 ItemEntity,然后询问某个时间范围内的关联价格历史记录。正如上面的文章中所讨论的,在 ItemEntity 中拥有该服务是不正常的,尽管它可以完成并使其工作。

在下面的示例代码中,我以不同的方式编写了此代码,即使用一个 Item 接口(interface),以及一个实际上是 ItemEntity 和 PriceCache 服务代理的实现。这是示例代码,缺少位;我认为(希望)有足够多的证据可以让大家清楚。

我的实体集及其属性并不是很大,我无法手动为所有实体执行此操作;几十个实体,每个实体有 5-20 个属性。这将是相当痛苦和无聊的,但它应该有效。

但是...是否有一种更简单的方法来创建本质上是代理对象并注入(inject)额外服务的对象?或者也许问题是,是否有更懒惰的方法来做到这一点?

@Entity @Table(name="item")
public class ItemEntity {
@Id @Column(name="id")
private long id;
@Column(name="name")
private String name;
/* ... setters, getters ... */
}

@Service
public class ItemCache {
@Autowired
private ItemDAO itemDAO;
@Autowired
private PriceCache priceCache;
private Map<Long,Item> itemCache;
public ItemCache() {
itemCache = new HashMap<>();
}
public Item get(long id) {
if (itemCache.containsKey(id))
return itemCache.get(id);
ItemEntity itemEntity = itemDAO.find(id);
Item item = (itemEntity == null) ? null : new ItemImpl(itemEntity, priceCache);
itemCache.put(id, item); // caches nulls to avoid retry
return item;
}
}

@Service
public class PriceCache {
@Autowired
private PriceDAO priceDAO;
/* ... various cache/map structures to hold previous query results ... */
public PriceCache() {
/* ... initialize all those cache/map structures ... */
}
public Collection<Price> getPrices(long id, LocalDateTime begTime, LocalDateTime endTime) {
Collection<Price> results;
/* ... check the caches to see if we already have the data ... */
/* ... otherwise, use priceDAO to find it and save the results in the cache ... */
return results;
}
}

public interface Item {
public long getId();
public String getName();
public Collection<Price> getPrices(LocalDateTime begTime, LocalDateTime endTime);
}

public class ItemImpl implements Item {
public ItemImpl(ItemEntity underlying, PriceCache priceCache) { ... }
public long getId() {
return underlying.getId();
}
public String getName() {
return underlying.getName();
}
public Collection<Price> getPrices(LocalDateTime begTime, LocalDateTime endTime) {
priceCache.get(getId(), begTime, endTime);
}
}

最佳答案

所以......我猜每个人都很有礼貌,并且不想同意我正在寻找一种懒惰的出路:-)

对于上面的示例,我没有这样做,但我有另一个类似的情况,我想要的本质上是一个添加了一些服务的 bean。我没有编写代理等,而是将提供服务的对象制作为派生对象。它不是 @Entity,而是纯粹根据 applicationContext.xml 描述创建的 @Component。

所以有四个部分;描述对象的 bean、使用/扩展描述并提供注入(inject)服务的“真实”业务对象,以及从描述查找并创建这些业务对象的缓存服务。

或多或少像下面这样。这是经过精简和即时编写的,因此可能有拼写错误;真正的代码和想法是有效的。

@Component
public class ThingDescr {
/* ... various attributes, setters, getters, just a bean ... */
}

public class Thing extends ThingDescr implements HelperService {
public Thing(ThingDescr td, HelperService svc) {
/* ... basically a copy constructor ... */
}
@Override
public void doSomething() {
/* ... whatever HelperService is supposed to do ... */
}
}

public interface HelperService {
public void doSomething();
}

@Service
public class ThingCache {
@Autowired
private HelperService svc;
@Autowired
private List<? extends ThingDescr> thingList;
private Map<String,Thing> thingMap;
private void load() {
thingMap = new HashMap<>();
for (ThingDescr td : thingList) {
Thing thing = new Thing(td, svc);
thingMap.put(thing.getName(), thing);
}
public getThing(String name) {
if (thingMap == null || thingMap.isEmpty())
load();
return thingMap.get(name);
}
}

此模式的主要优点是业务对象“Thing”继承底层对象的所有属性,而无需编写它们。我没有这样做,但我认为如果属性应该是只读的,那么“ThingDescr”中的 setter 可以受到保护,以便“Thing”可以访问它们,但该类的用户不能。

关于java - Spring 和 Hibernate 混搭,是 @Entity 的代理对象,并添加了额外的 @Service,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60856510/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com