I have the following classes and interfaces(simplified to make things clear).
#Serivce
class Service1 {
#Cacheable("cacheName")
public Metadata preLoadMetadata() {
// load data from database
}
}
#Service
class Service2 implements Loader {
#Autowired #Lazy
private Service1 service1;
#Overrride
public CacheWrapper getCacheWrapper() {
return new CacheWrapper(() -> service1.preLoadMetadata());
}
}
interface Loader {
CacheWrapper getCacheWrapper();
}
class CacheWrapper {
private Callable callable;
public CacheWrapper(Callable callable) {
this.callable = callable;
}
public getCallable() {
return callable;
}
}
The Spring bean responsible for loading the cache at the time of deployment.
#Component
class LoadCache {
#Autowired
private List<Loader> allLoaders;
#PostConstruct
public void load() {
allLoaders.getCacheWrapper().getCallable().call();
}
}
preLoadMetadata() doesn't save the data in the cache but it does execute. After deployment is complete and I call the same method preLoadMetadata() again, then it saves the data in the cache.
Why does #Cacheable doesn't work at the time of deployment?
If I manually use put method of Cache to populate cache inside method annotated with #PostConstruct, I am able to do it successfully while deployment.
I am using Tomcat as server.
I am using Couchbase cache behind Spring cache abstraction.
If you want to preload your cache I suggest you use an ApplicationListener that will execute once your application has started:
#Component
public class CacheInitializer implements ApplicationListener<ContextRefreshedEvent>{
#Autowired
private List<Loader> allLoaders;
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
allLoaders.getCacheWrapper().getCallable().call();
}
}
The root cause for not working of Cacheable annotation:
afterSingletonsInstantiated() method sets the initialized flag to true only when BeanFactory has instantiated all the beans. If the initialized flag is false, no caching operations are performed. Here, inside the post construct, when we start pre-loading caches, then it is highly probable that LoadCache is not the last bean to be instantiated. Hence, no caching operations are performed(while using caching annotations).
Hence, EventListener annotation responding to ContextRefreshEvent is the best thing to use in this case which ensures that the context has started and then only loading of caches take place.
Related
In Spring, beans are encapsulated by a proxy object and when called from outer object the proxy object's method is also called. By using this trick transaction management is performed in proxy object's methods.
But when you are calling a method in the same bean and if you want the called method to be run in another transaction with the caller method it is not possible. Since the method calls in the same bean does not pass through the proxy object which performs transaction operations.
In order to solve this, self-injection of the bean inside itself is proposed.
like this
#Service
public class MyService{
#Autowired
public MyService myService;
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void method1(){
method2();// runs in the same transaction with method1
myService.method2();// runs in separate transaction from method1
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void method2(){
}
}
I want to ask whether self-injection leads to memory leakage.
Outer bean MyService includes injected myService and myService should include attribute of type MyService, which should include attribute of type MyService ....
The service is not copied, it is only a reference. But I'd be wary of such a design: it creates a circular reference and the object graph is impossible to create at once. You first need to create the incomplete service, then set its field. Furthermore, it is kind of confusing and surprising to find such a dependency to self
I'd propose a different solution:
#Component
public class WithTransaction {
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void requiresNew(final Runnable runnable) {
runnable.run();
}
}
#Service
public class MyService{
private final WithTransaction withTransaction;
#Autowired
public MyService(final WithTransaction withTransaction) {
this.withTransaction = withTransaction;
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void method1(){
method2();// runs in the same transaction with method1
withTransaction.requiresNew(this::method2); // runs in separate transaction from method1
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
public void method2(){
}
}
And if you can avoid it: don't call any public methods from your service on the service itself. Split the service into smaller components so that each "public" call must go through the proxy.
For my design I need a controllable schedular. Spring boot offers an #Scheduled annotation but that is more simplified and I do not have granular control.
So I wanted to implement my own scheduler manually.
This is the class I created:
#Slf4j
#Service
public class JobExecutor {
private static ScheduledExecutorService jobExecutor;
private static Environment env;
#Autowired
private JobExecutor(Environment env) {
JobExecutor.env = env;
}
public static ScheduledExecutorService INSTANCE() {
if (null == jobExecutor) {
synchronized (JobExecutor.class) {
if (null == jobExecutor) {
jobExecutor = Executors.newScheduledThreadPool(
Integer.parseInt(Objects.requireNonNull(env.getProperty("scheduler.jobs"))));
}
}
}
return jobExecutor;
}
}
With this approach I could simply call the static method to get a single instance.
Is this correct approach for a schedular? I need to start and stop and shutdown the jobs. I tried guava AbstractScheduledService but that does not seem to be working.
This is not the correct approach for creating a singleton, because double checked locking is broken. You're using Spring, so a) your JobExecutor will be a singleton anyway, and b) will only be created if it is needed. You might as well, therefore, create your executor instance in the constructor and get rid of those static methods.
Even better, you could create schedulers as named beans, and then inject them into classes where you want them:
#Configuration
public class ExecutorConfiguration {
#Bean
public ScheduledExecutorService jobExecutor(#Value("${scheduler.jobs}") jobs) {
return Executors.newScheduledThreadPool(jobs);
}
}
This says that whenever another component needs a ScheduledExecutorService, Spring should call this jobExecutor() method; Spring will automatically populate the jobs parameter from the scheduler.jobs property because of the #Value.
You can then inject your executor wherever you need it, for example with constructor injection (handily you're already using Lombok, so the amount of boilerplate is minimised):
#Service
#AllArgsConstructor
public class MyThingThatNeedsAScheduler {
private final ScheduledExecutorService jobExecutor;
// methods here...
}
You can also use setter or member injection, if you want.
I was trying to update the table row data from outside the controller (Inside some threads) and getting 'NullPointerException' always.
Thread code:
public class S3Thread implements Runnable {
#Autowired
private IAutomationService automationService;
#Override
public void run() {
Automation config = new Automation("user1","success");
automationService.updateAutomation(config);
}
}
NullPointer exception thrown on below line:
automationService.updateAutomation(config);
Note: I was able to create/update from the controller class.Only in Thread.
Well, this is the classical Why is my Spring #Autowired field null case. You create the S3Thread instance by yourself, and thus, no beans are injected into it.
Considering you're trying to just do something in a separate thread, you can consider using #Async:
#Async
public void updateAutomationConfiguration() {
Automation config = new Automation("user1", "success");
automationService.updateAutomation(config);
}
Notes:
You have to add the #EnableAsync annotation to any configuration class (eg. your main class) to make this work.
Spring uses proxying by default, which means that you can't add this updateAutomationConfiguration() class to your controller itself. Direct calls to methods within the same bean bypass the proxied logic. The solution is to put this method in a separate bean which can be autowired and invoked from within the controller. I've provided more detailed answers about alternative solutions in this answer.
Spring also has a getting started guide for creating asynchronous methods.
Alternatively, there are also some ways to execute asynchronous calls within controllers, for example by using CompletableFuture within a controller:
#PutMapping("/automation/configuration")
public CompletableFuture<String> updateAutomationConfiguration() {
return CompletableFuture.supplyAsync(() -> {
Automation config = new Automation("user1", "success");
return automationService.updateAutomation(config);
});
}
Related: How to create a non-blocking #RestController webservice in Spring?
Spring does not scan your runnable as it is not annotated with #Component.Try annotating it with #Component/#Service.
Don't forget to set scope required scope though!
There are 2 potential solutions to your problem:
Either you need to make S3Thread class a service by annotating it with #Service or #Component and autowiring it on the calling class, or you can alternatively use the constructor for initializing your automationService, e.g. private IAutomationService automationService = new AutomationService();
Since your thread class is not managed by spring you will not be able to inject the spring managed beans in the S3Thread class.
In order to do that you need to create a class or factory which should be hooked into the spring life cycle.
Once you have the hold of that class you can get the appropriate bean and pass the reference onto/or used in the S3Thread class directly. Something like this
#Component
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext ctx;
#Override
public void setApplicationContext(ApplicationContext appContext)
{
ctx = appContext;
}
public static ApplicationContext getApplicationContext() {
return ctx;
}
}
public class S3Thread implements Runnable {
#Override
public void run() {
Automation config = new Automation("user1","success");
IAutomationService automationService=
ApplicationContextUtils.getApplicationContext().getBean(IAutomationService .class);
automationService.updateAutomation(config);
}
}
I am searching for a way to read and parse a lot of data when the spring boot app is starting and be able to use these data later in other classes.
I started with a class DataRepository.java and annotated it with #Service to be able to inject it later. I'm planning to read the data here and to inject it in any other class I need the data.
But how can I achieve to parse the data just once and at app startup? The spring boot app should only be reachable if the parsing is done.
Your approach with #Service is 100% appropriate.
By default all beans are singletons, so if you parse data on bean creation (in constructor) it will be parsed only once, and this info can be used in other beans by simple injection.
Please note that if during data parsing you have to use other beans, you should be confident that all beans are completely constructed. For that you should use approach proposed by #jreznot:
https://stackoverflow.com/a/51783858/5289288
You can use ContextStartedEvent and handle it:
#Component
public class ContextStartedListener implements ApplicationListener<ContextStartedEvent> {
#Override
public void onApplicationEvent(ContextStartedEvent cse) {
System.out.println("Handling context start event. ");
}
}
See also: https://www.baeldung.com/spring-events
By default all beans in spring context are singletons. Spring guarantees that it will creates a bean just ones during context loading.
For example if you will have few contexts in your application it creates one instance for every context.
If you have just one context you can use these approaches:
initialize data in constructor. Data will initialized and ready to
use just after bean's instance creation.
#Component
public class DataRepository {
public DataRepository() {
... init data
}
}
use #Bean annotation withinit method. Allows you don't stick to Spring in
your data repository and initialize data after all beans were created.
public class DataRepository {
public void init() {
... init data
}
}
#Configuration
public class DataRepositoryConfiguration {
#Bean(initMethod = "init")
public DataRepository dataRepository() {
return new DataRepository();
}
use #Bean annotation and invoke init method. Allows you don't stick to
Spring in your data repository, but #Autowired field will uninitialized.
public class DataRepository {
public void init() {
... init data
}
}
#Configuration
public class DataRepositoryConfiguration {
#Bean
public DataRepository dataRepository() {
DataRepository dr = new new DataRepository();
dr.init();
return dr;
}
}
use #PostConstruct annotation. Initialize data after all beans was
created.
public class DataRepository {
#PostConstruct
public void init() {
... init data
}
}
Exception thrown during initializing will stop Spring's context initializing
You can use PostConstruct on any bean. For example
#Component
class DataLoad {
......
......
#PostConstruct
public void parseData() {
...... do your stuff here.......
}
}
With this the code inside parseData will be called only once. This is a very common way to do things in scenarios like when you want to load some configuration data from database at the start of the application and do it only once. In these cases you can #Autowired the repository class to the same class and use that in your #PostConstruct method and get data
I have a Java Project with Spring MVC.
I need to start TimerTasks already after my application is initialized, so I implemented the WebApplicationInitializer Interface and I call it SystemInitializer. Inside that class I have a #Autowired property, that #Autowired property is a DAO class.
I need it cause I want to execute some tasks based in recordings from my data base. But that Autowired property is ever null.
public class SystemInitializer implements WebApplicationInitializer {
#Autowired
private DomainResearchDao domainResearchDao;
#Override
public void run() {
if (this.domainResearchDao != null) {
System.out.println("OK");
}
// always here
else{
System.out.println("NO OK");
}
}
You can not use #Autowired inside of WebApplicationInitializer.
Your Beans are not ready (not scanned yet) to be injected. Your Application has no idea what DomainResearchDao is at that moment.
Spring can autowire beans only after your application is initialized and all (singletone) instances (#Component, #Service etc.) are created.
If you want to do some job after your application is started, use Spring Event for doing this:
#Component
public class DoOnStart{
#Autowired
private IYourService service;
#EventListener
public void handleContextRefresh(ContextRefreshedEvent e) {
// your CODE
}
}
Just implement this class, no need to autowire it.