Getting null session in spring startup class - java

Follow up to my existing question, I am getting null session factory and hence my transaction is being failed. Here is what my class structure looks like
#Component
public class MyCachingObj extends HibernateMapper{
#PostConstruct
public void loadAll() {
...
getCurrentSession().getQuery(); //this method is in HibernateMapper
...
}
}
#Repository
public class HibernateMapper {
#Autowired
private SessionFactory _session;
public Session getCurrentSession() {
return _session;
}
}
What I have read so far, that #PostConstruct doesn't guarantee that spring is done with all beans. Then how can i make sure that spring is done processing and i have session ready to be picked up ?
EDIT
I ended up creating
#Component
#Transactional
#Repository
public class ApplicationStartup implements ApplicationListener<ContextRefreshedEvent>{..}
which had autowired sessions and autowired another Component class. However, i noticed that this onApplicationEvent method was being called twice. I ended up putting a boolean variable to load the underlying data only once.
Now few questions
Why onApplicationEvent is being called twice.
My cached object is annotated with #Component, Is it safe to assume that as long as that object is being used by #Autowired instance, it would remain singleton and would hold the data i loaded at startup ?

Related

Cannot Inject Service in HandlerInterceptorAdapter, Getting NullPointerException

I have a service-client project which is in normal spring application , not spring boot .its used for mainly logging related things.which contains Interceptor , loggingservice impl class and some model classes for logging. I have added this module as a dependency to main application in pom.xml.and i was able to inject and use the loggingService beans within the service layers of the main application.
Am getting NullPointerException while auto-wiring loggingService within the interceptor .The bean is not available within the interceptor.but like i said it can be injected and used within the main application.
Also am not able to read properties using #Value within the interceptor.
This is my Interceptor class .
#Component
public class LoggingInterceptor extends HandlerInterceptorAdapter {
#Autowired
LoggingService loggingService;
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
loggingService.info("Am in prehandle");
return true;
}
}
This is my configuration class where i register the interceptor with the main application
#Component
public class LoggingConfig implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getLoginInterceptor());
}
#Bean
public LoggingInterceptor getLoginInterceptor() {
return new LoggingInterceptor();
}
}
My question is almost similar to this post Cannot Autowire Service in HandlerInterceptorAdapter , but its different like am referring the interceptor from another module , and like they suggested i tried to create the bean from the application.
But the issues am facing right now is
getting NullPointerException while injecting loggingService within interceptor, but its working in main application
#Value annotation also return null, not able to read from properties
You have 2 possible solutions.
Mark your LoggingConfig as #Configuration instead of #Copmponent
Inject the LoggingInterceptor instead of referencing the #Bean method
Option 1: LoggingConfig as #Configuration
Your LoggingConfig is marked as an #Component whereas it should be marked as an #Configuration. The difference is that whilst it is allowed to have an #Bean method on an #Component it operates in a so-called lite mode. Meaning you cannot use method references to get the instance of a bean (this is due to no special proxy being created). This will lead to just a new instance of the LoggingInterceptor being created but it isn't a bean.
So in short what you are doing is equivalent to registry.addInterceptor(new LoggingInterceptor()); which just creates an instance without Spring knowing about it.
When marking the LoggingConfig as an #Configuration a special proxy will be created which will make the LoggingInterceptor a proper singleton bean, due to the method call being intercepted. This will register the bean in Spring and you will be able call the method.
NOTE: You actually endup with 2 instances of the LoggingInterceptor one due to the #Component on it the other through the #Bean. Remove the #Component.
Option 2: Inject the LoggingInterceptor.
As your LoggingInterceptor is marked as an #Component Spring will already create an instance (you actually have 2 instances of it created in your current setup). This instance you can inject into your LoggingConfig.
#Component
public class LoggingConfig implements WebMvcConfigurer {
private LoggingInterceptor loggingInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loggingInterceptor);
}
}
With this you can remove the #Bean method as you will get the proper one injected into your LoggingConfig class. The class can also remain an #Component in this case. Although I would recommend using #Configuration as to also properly stereotype it.
NOTE: If you are on a recent Spring version you can use #Configuration(proxyBeanMethods=false). This will make a lite-configuration (just like an #Component) but it is still marked properly as a configuration class.

Why Spring Bean Self Invocation is working here for Transaction

Environment :
Tomcat 6
Spring 4
Hibernate 4
Spring MVC
Code :
I have below service layer class :
public interface AbhisheskService {
public List<AbhishekDTO> findByMatchingCriteria(AbhishekDetailsSearchDTO searchDto);
}
#Service("abhishekService")
public class AbhishekServiceImpl implements AbhisheskService {
#Autowired
private AbhishekDao abhishekDao;
#Transactional
public List<AbhishekDTO> findByMatchingCriteria(AbhishekDetailsSearchDTO searchDto) {
return getAbs();
}
public List<AbhishekDTO> getAbs(){
Abhishekdetails absDt = this.abhishekDao.get(4L);
return null;
}
}
The AbhishekDao is a standard DAO layer interface which extends GenericDAO super interface.
public interface AbhishekDao extends GenericDAO<Abhishekdetails, Long>{
public List<Abhishekdetails> findByMatchingCriteria(AbhishekDetailsSearchDTO searchDto);
}
My question is :
findByMatchingCriteria method is marked with #Transactional.
This method calls another method getAbs which is NOT MARKED AS #Transactional and it is invoked within findByMatchingCriteria (self-invocation).
As per my understanding since :
1)findByMatchingCriteria is calling getAbs within itself (self-invocation) , getAbs() method SHOULD NOT run inside transaction. Since it is bypassing dynamically created proxy here
2)Moreever getAbs doesn't have #Transactional annotation on it.
3)But when getAbs calls this.abhishekDao.get(4L) everything works fine and a record with ID 4L is retrieved. The DAO bean is calling sessionFactory.getCurrentSession() inside it to get object from Db. But why is this working ?
Since there SHOULD NOT BE any active transaction.
4)Why is above code working ? A lot of posts on Spring Transaction management state that self invocation will not work. (Even spring docs).
Then why is above set up working ?
Am I amissing anything here ?
Or My understanding of spring transaction is incorrect?
Please repply as I am getting confused here
The way it works is:
- AbhishekServiceImpl bean is wrapped in a proxy.
findByMatchingCriteria is #Transactional, so before the method is invoked Spring gets new database connection from the connection pool and sets auto commit to false.
The transactions are bound to a thread, so the other methods on this thread will use this connection.
The methods findByMatchingCriteria and getAbs are executed
after findByMatchingCriteria Spring calls commit on the connection(or rollback if RuntimeException occurs).
So your code is in transaction that's around findByMatchingCriteria
A case where a transaction will not be created is if you have #Transactional on getAbs , but not on findByMatchingCriteria(reverse the calling) and you call findByMatchingCriteria outside of the service. But if you call only getAbs outside of the service it will be in transaction.
More clear example:
#Service
public class MyServiceImpl implements MyService{
#Autowired
private MyDao myDao;
#Transactional
public List<T> transactionalMethod() {
return this.myDao.get(4L);
}
public List<T> notTransactionalMethod(){
return transactionalMethod();
}
}
In some other class:
#Component
public class SomeClass {
#Autowired
private MyService myService;
public void someMethod(){
myService.transactionalMethod();//will be in transaction. Here actualy you go to the proxy first and then it calls the real method.
myService.notTransactionalMethod();//will not be in transaction and hibernate will throw an error.
//You go to the proxy, but doesent do anything special because the method is not transactional and it calls the real method,
//but here you dont't got trough the proxy so the #Transactional is ignored.
}
}

Why in Spring I am not allowed to annotate a final class with #Configuration?

I am studying for the Spring Core certification and I have some doubts related to the answer of this question founded on the study material stuff.
Why are you not allowed to annotate a final class with #Configuration
My reasoning is the following one for substantiate this assertion:
Consider the following configuration class:
#Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository();
}
#Bean
public TransferService transferService() {
TransferServiceImpl service = new TransferServiceImpl();
service.setAccountRepository(accountRepository());
return service;
}
#Bean
public AccountService accountService() {
return new AccountServiceImpl(accountRepository());
}
At first look this situation could appear strange because the first method (accountRepository()) instantiates an JdbcAccountRepository object as a bean having id=AccountRepository that, following the Spring default behavior, is a singleton
The second and the third method call twice more time the accountRepository() method that should instantiate twice more JdbcAccountRepository objects and this is not possibile because it is singleton !!!
So, to solve this situation Spring use the Inheritance-based Proxies strategy that expect to create a child class of my configuration class (the one annoted by #Configuration) and it is does:
For each bean, an instance is cached in the child class
Child class only calls super at first instantiation
So the child class is the entry point because the following behavior is implemented by this child class:
public class AppConfig$$EnhancerByCGLIB$ extends AppConfig {
public AccountRepository accountRepository() {
// if bean is in the applicationContext
// return bean
// else call super.accountRepository() and store bean in context
}
public TransferService transferService() {
// if bean is in the applicationContext, return bean
// else call super.transferService() and store bean in context
}
.....................................................
.....................................................
.....................................................
}
So if I annotate a configuration class with final Spring can't have this behavior because in Java a final class cannot be subclassed
Is it correct?
Using the same reasoning can I also assert that in Spring I can't have a final method annoted with #Bean annotation?
Because, as shown in the previous example, I have that when at startup time is created the child class (the proxy) of my configuration class happens that for each bean, an instance is cached in the child class and if it is final it is not possible (but I am absolutly not sure about this assertion)
Am I missing something? Can you give me the exact explaination?
Tnx
Spring creates dynamic proxies for classes annotated with #Configuration classes. Spring uses CGLIB to extend your class to create proxy. Hence, configuration classes cannot be final.
Regarding accountRepository() being invoked twice:
If you invoke accountRepository() method to create an instance, it is no more a Spring managed bean. Spring will not have any idea of the instances created in this manner. Hence, you will end up with multiple instances of JdbcAccountRepository
You can preserve the singleton behavior if you configure as below:
#Bean
public TransferService transferService(JdbcAccountRepository jdbcAcctRepo) {
TransferServiceImpl service = new TransferServiceImpl();
service.setAccountRepository(jdbcAcctRepo);
return service;
}
#Bean
public AccountService accountService(JdbcAccountRepository jdbcAcctRepo) {
return new AccountServiceImpl(jdbcAcctRepo);
}

inject stateless bean into a singleton bean

I have this requirement: I have a singleton bean and I have a method annotated with #PostConstruct where I perform some initialization. One of the initialization is to read some values from a DB, so I want to inject in this method a Stateless bean which is a service bean that access the DB. I don't want to inject the stateless bean as a field in the singleton bean because it is needed only in this method (nowhere else in the singleton bean). To do so I did wrote this in singleton bean:
#Singleton
public class MySingletonBean {
#PostConstruct
#EJB
public void init(SLSBService service) { /* use service to read from DB */ };
...
}
The problem is that the Singleton bean can not be instantiated. Any idea? Thank you in advance.
As the #PostConstruct annotated (callback) method is actually called after all references are resolved (all beans injected) I do not think this construct works.
What you could do or try out is to remove the #PostConstruct and using normal setter injection. However, be aware that other injected resources have not necessarily been resolved at this time.
#EJB
public void setService(SLSBService service){
service.doSmg();
}
#Stateless
public class SLSBService{
#PersistenceContext
private EntityManager em;
#TransactionAttribute(TransactionAttributeType.MANDATORY)
public void doSmg() {
Member member = new Member();
member.setEmail("bla#bla.de");
member.setName("fubu");
member.setPhoneNumber("453454534535");
em.persist(member);
}
}
/* edit */
Just had some time for trying it out. The construct should be usable for DAOs, as the method is executed within a transaction and also the EntityManager (within the SLBService) is injected properly. And as expected references to other EJBs have not be resolved yet, so be aware of that.

#Transactional method called from another method doesn't obtain a transaction

In Spring, a method that is annotated with #Transactional will obtain a new transaction if there isn't one already, but I noticed that a transactional method does not obtain any transaction if it is called from a non-transactional one. Here's the code.
#Component
public class FooDao {
private EntityManager entityManager;
#PersistenceContext
protected void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Transactional
public Object save(Object bean) {
return this.entityManager.merge(bean);
}
public Object saveWrap(Object bean) {
return save(bean);
}
}
#Component
public class FooService {
private FooDao fooDao;
public void save(Object bean) {
this.fooDao.saveWrap(bean); // doesn't work.
this.fooDao.save(bean); // works
}
}
saveWrap() is a regular method that calls save() which is transactional, but saveWrap() won't persist any changes.
I'm using Spring 3 and Hibernate 3. What am I doing wrong here? Thanks.
It is one of the limitations of Springs AOP. Because the dao bean is in fact a proxy when it is created by spring, it means that calling a method from within the same class will not call the advice (which is the transaction). The same goes for any other pointcut
Yes, this is expected behaviour. #Transactional tells spring to create a proxy around the object. The proxy intercepts calls to the object from other objects. The proxy does not intercept calls within the object.
If you want to make this work, add #Transactional on the method that is invoked from "outside".
This is a bit late I know, but would just like to add a way to overcome this limitation is that within the method obtain the spring bean from the application context and invoke the method. When the spring bean is obtained from the application context it will be the proxy bean not the original bean . Since the proxy bean is now invoking the method instead of the original bean the transaction advice will be implemented on it.
A possible workaround is to call the method like if it was invoked from "outside"
You can do it by getting the current proxy of the component and then call the method :
((MyService) AopContext.currentProxy()).innerMethod();
Source: https://www.programmersought.com/article/58773839126/

Categories

Resources