Spring service with in-memory list - spring

I want to have a service which keeps a list inmemory so I don't need to access the database everytime. The service is accessed by a controller. Is this a valid approach or am I missing something? What about concurrent access here (from the controller)? Is this (stateful service) an anti-pattern?
#Service
public class ServiceCached {
private List<SomeObject> someObjects;
#PostConstruct
public void initOnce() {
someObjects = /** longer running loading methodd **/
}
public List<SomeObject> retrieveObjects() {
return someObjects;
}
}
Thanks!

I wouldn't call it an anti-pattern, but in my opinion loading the list from the database in a #PostConstruct method is not a good idea as you slow down the start up of your application, I'd rather use a lazy loading mechanism, but this would potentially introduce some concurrent access issues that would need to be handled.
In your example concurrent access from the controller should not be a problem as the list is loaded from a #PostConstruct method and the controller would depend on this service, therefore this service would need to be fully constructed before it is injected into the controller, therefore the list would already be loaded.
Preferably I'd suggest using Spring Caching: Caching Data with Spring, Documentation, Useful guide
Usage example:
#Cacheable("books")
public Book getByIsbn(String isbn) {
simulateSlowService();
return new Book(isbn, "Some book");
}
This way you do not need to take care of loading and evicting the objects. Once set up, the caching framework will take care of this for you.

Related

Understanding Redis inside Spring Boot

I have a Spring Boot application, where I need to get data from a table when the app initializes.
I have a repository with the following code:
#Repository
public interface Bookepository extends JpaRepository<Book, Integer> {
Proveedor findByName(String name);
#Cacheable("books")
List<Proveedor> findAll();
}
Then from my service:
#Service
public class ServiceBooks {
public void findAll(){
booksRepo.findAll();
}
public void findByName(String name){
booksRepo.findByName(name);
}
}
And then I have a class that implements CommandLineRunner:
#Component
public class AppRunner implements CommandLineRunner {
private final BookRepository bookRepository;
public AppRunner(BookRepository bookRepository) {
this.bookRepository = bookRepository;
}
#Override
public void run(String... args) throws Exception {
bookRepository.findAll());
}
}
So here,when the application initializes, it queries to the Books table and caches the result. Inside the application each time I call find.all(), the cache is working, and I get the data from my cache.
So here are my 2 questions:
About Redis, I am not using Redis and I am doing database cache without any problem. So, where does Redis fit into this approach? I don't understand why everybody uses Redis when cache is working without needing other libraries.
When I call findByName(name), is there any chance to execute that query over the data I already have cached? I know I can have a cache on that method, but the cache will save data each time I search a particular name. If a name is searched for the first time, it will go to the database for that value. I don't want that, I would like that Spring performs the query using the data from the first cache where I have all Books.
The answers to your question
Redis avoids the DB call as it stores your response in Memory. You can use #cacheable even in controller or service. If you use #cacheable in controller, your request will not even execute the controller method, if it is already cached.
for FindByName, Redis provides a nice way to store the data based on keys.
Refer the link Cache Keys.
Once you request by Name, it will get the data from DB, the next time you request with same name, it will get from cache based on the key.
Coming back to your question, NO you should not do a search on your cached data, as caches are highly volatile, you cannot trust the data from cache. also searching through the cached data might affect the performance and you might need to write lines of unneeded additional code.
Spring boot manages the cache per application or per service. When you are using multiple instance of a service or app then certainly you'll want to manage the cache centrally. Because per service cache is not usable in this case because what one app caches in its own spring boot is logically not accessible by another apps.
So here Redis comes into picture. If you use Redis, then each instance of service will connect to the same Redis cache and get the same result.

Good usage of managed entities / proxies with ORM

I'm currently thinking about how i handle my domain objects along with hibernate considering the following :
My model object are directly annotated with JPA annotation, no entity layer.
On some database heavy operation, i don't mind tuning my code so i take full advantages of the proxies, even if we can consider it as a leak of abstraction/implementation masking. Of course i prefer when i can do otherwise.
Because i don't have entity layer, i don't have a DAO layer, the entity manager is considerered itself as a DAO layer (related : I found JPA, or alike, don't encourage DAO pattern)
However i was thinking about improve what i'm doing know in order to reduce a bit the complexity, or at least, relocate that complexity in a place it fits better, like entity's related service. And maybe more abstract the fact that i'm using an ORM.
Here is a generic CRUD Service from which all my business service inherits. This code is to show you how things are done currently (annotation, logs remove for clarity) :
public void create(T entity) {
this.entityManager.persist(entity);
}
#Transactional(value = TxType.REQUIRED, rollbackOn=NumeroVersionException.class)
public void update(T entity) throws NumeroVersionException{
try{
this.entityManager.merge(entity);
}catch(OptimisticLockException ole){
throw new NumeroVersionException("for entity "+entity, ole);
}
}
public T read(int id) {
return this.entityManager.find(entityClass, id);
}
public void delete(int id) {
T entity = this.entityManager.getReference(entityClass, id);
this.entityManager.remove(entity);
// edit : removed null test thanks to #JBNizet
}
The problem with this kind of implementation, is that if i want to create an object, then use the advantages of the proxies i basically have to create it then refetch it. Of course the query may not hits the database but hits only hibernat's cache (not sure about it though). But that means i still have to not forget to refetch the proxy.
This mean i leak the fact that i'm using an ORM and proxies behind the scenes.
So i was thinking to change my interface to something like :
public T read(int id);
public T update(T t)throws NumeroVersionException;
public T create(T object);
public void delete(int id);
List<T> list();
Meaning once i pass an object to this layer, i will have to use the returned value.
And implements update specifically like :
public T update(T t){
if(!(t instanceof [Proxy class goes there])){
//+ check if it is a detached proxy
entityManager.merge(t);
}
}
Since merge hits the database every time called, for some operation involving just some 10ish entities this can be annoying i wouldn't call it in an update method with a proxy.
Of course I expect to have some edge cases where i'll need the entityManager to flush things and so on. But i think this would reduce significatively the current complexity of my code and isolate better the concerns.
What i'm trying in short is to relocate the ORM code within the service so i can hide the fact that i'm using an ORM and proxies and use the interface like i was using any other implementation without loosing the benefits of using an ORM.
The question is so :
Is that new design a good idea towards this idea ?
Did i miss anything about how to handle this properly ?
Note : Even though i'm talking about performance, my concern is also about isolation of concerns, maintenability, and easier usability for developers that aren't familiars with ORMs and Java which i work with.
Thanks to #JBNizet i'm seeing some thing more clearly :
I should use the value returned by merge() method.
A managed entity is not always a proxy.
I don't have to abstract the fact that i use managed entities, this will lead to complex and unefficient code
I choosed JPA i won't switch for it which is true unless rewriting the full model to stand for something based on non relationnal database.
So i'll just change my update method from the original code and i'll keep the rest.

Store data not in database

I want to implement simple chat but store them only during server work. I don't want to store them in database, just like in List or Map. How to?
This solution works for "Simple" chat as you explained.
There isn't much information on how you had built this before so I'm just going to explain how to have an Application scoped bean that can be injected into other beans to handle storing chat.
You can configure a Service to store this information.
ChatHistoryService.java
#Service
#Scope("application")//This is the key this will keep the chatHistory alive for the length of the running application(As long as you don't have multiple instances deployed(But as you said it's simple so it shouldn't)
public class ChatHistoryService {
List<String> chatHistory = new LinkedList<>();//Use LinkedList to maintain order of input
public void storeChatMessage(String chatString) {
chatHistory.add(chatString);
}
public List<String> getChatHistory() {
//I would highly suggest creating a defensive copy of the chat here so it can't be modified.
return Collections.unmodifiableList(chatHistory);
}
}
YourChatController.java
#Controller
public class YourChatController {
#Autowired
ChatHistoryService historyService;
...I'm assuming you already have chat logic but you aren't storing the chat here is where that would go
...When chat comes in call historyService.storeChatMessage(chatMessage);
...When you want your chat call historyService.getChatHistory();
}
Once again keep in mind that this really only works for a simple application. If it's distributed there will be different chat histories per instance of the application at that point you could look into a distributed cache.
In any case don't go beyond simple with this implementation.
If you look here it will give you an idea of several caches that work with spring boot.
https://github.com/spring-projects/spring-boot/tree/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache

Accessing Spring #Transactional service from multiple threads

I would like to know if the following is considered safe.
Usual Spring service class that accesses a bunch of DAOS / hibernate entities:
#Transactional
public class MyService {
...
public SomeObject readStuffFromDB(String key) {
...
//return some records from the DB via hibernate entity etc
}
A class in the application that has the service wired in:
public class ServiceHolder {
private MyService myService;
private SomeOtherObject multiThreadedMethod() {
...
//calls myService.readStuffFromDB() and uses the results
//to return something useful
}
multiThreadedMethod will be called from multiple threadpool threads. I would like to know if the multiThreadedMethod is safe in its calls to myService.
It is NOT making any modifications to the DB - only reading.
What happens if two threads call myService.readStuffFromDB() at exactly the same time? Will a concurrent modification exception be thrown from somewhere?
I've been running it with no issues but I'm not 100% sure it will always work.
Yes you will call the same object in the same time as long as your service bean is defined as singleton (which is default and proper), but you should not rely on local variables in you services. So the methods should be written that way they can work independently (you don't need a mutual exclusion here). If you called db and tried do any operations nothing would happen because every thread would receive a new instance of entity manager. If you modified db in the same time and any type of db exception was thrown you would get a rollback exception which is perfectly fine.
entityManager.persist() will do more or less entityManager.getEntityManagerAssignedToCurrentThread().persist()
It is a proxy not real object. So you are safe :)

Domain driven design - access modifiers for entities and enforcing validation

I am very new to DDD and reading various discussions on validation (where to put it) on the stackoverflow as well as on the web. I do like the idea of keeping the validations outside the entities and validate them depending upon the context. In our project, we have an entity called MedicalRecord and there are various rules for when one can be created or can be saved. I want to create a service layer, let's say RecordService, that would do some check to make sure if a user can create a medical record before creating one. I also want to create MedicalRecordRepository that would save the medical record. What confuses me is the access modifies on my entity and repository classes. Since both will be public, how can I enforce the client of my application to use the service instead of just creating new medical record (with public constructor) and use the repository to save it? I am using c#. I know DDD is language independent but wondering if someone could provide some thoughts on this.
Thanks.
You must control record creation by making the c'tor non-public and allowing creation only through a factory:
public class MedicalRecord
{
internal MedicalRecord()
{
}
}
public static class MedicalRecordFactory
{
public static MedicalRecord Create(User onBehalfOf)
{
// do logic here
return new MedicalRecord();
}
}
For the internal keyword to be applicable, either both classes must be in the same assembly or the class assembly must allow the factory assembly access with the InternalsVisibleTo attribute.
Edit
If you need to be able to perform validation at any time, you additionally have to encapsulate validation logic in another class (here partially done via an extension method):
public static class MedicalRecordValidator
{
public static bool IsValid(this MedicalRecord medicalRecord, <context>)
{
return IsValid(<context>);
}
public static bool IsValidForCreation(User onBehalfOf)
{
return IsValid(null, onBehalfOf);
}
private static bool IsValid(<context> context, User user = null)
{
// do validation logic here
}
}
then, the factory could do this:
public static MedicalRecord Create(User onBehalfOf)
{
return IsValidForCreation(onBehalfOf) ? new MedicalRecord() : null;
}
and you could also always do this:
if (myMedicalRecord.IsValid(<context>))
{
// ....
Only use your repository to retrieve your entities; not to save them. Saving (persisting) your entities is the responsibility of your unit of work.
You let your service change one or more entities (for instance a MedicalRecord) and track the changes in a unit of work. Before committing the changes in your unit of work, you can validate all entities for validation needs across entities. Then you commit your unit of work (in a single transaction), which will persist all your changes, or none at all.
For clarity, your MedicalRecord should protect its own invariants; such that a client retrieving a MedicalRecord using a repository, calling some methods to modify it and then persisting it using a unit of work, should result in a "valid" system state. If there are situations where this is not the case, then it can be argued that it should not be possible to retrieve a MedicalRecord on its own - it is part of some larger concept.
For creation purposes, using a factory like #Thomas suggests below is a good approach, although I think I'd call it a service (because of the collaboration between entities) instead of a factory. What I like about Thomas' approach is that it does not allow a client to create a MedicalRecord without a User (or other contextual information), without tying the MedicalRecord tightly to the user.

Resources