Spring - "late binding" autowired beans - java

Let's say I have the following dependencies:
#Configuration
public class MyCfg {
// ...
#Bean
public Session session() {
return sessionFactory().getCurrentSession();
}
}
#Repository
#Transactional
public class MyRepo {
#Autowired
private Session session;
}
sessionFactory() is set up properly. If I inject SessionFactory instead of Session, it works just fine. However, if try and inject Session, it dies with an exception on container bootstrap because there is no session bound to thread.
Since the repository is #Transactional, I know that at run time there will be a session. How can I make it work, so that it injects AOP-initialized Session at run time, but does not try and resolve it when the repo is instantiated?

I would take a look at this bit of Spring documentation regarding bean scopes. Near the bottom they show how to use the #Scope annotation, which you will want to apply to your session() method in MyCfg. It sounds like you would want to use the 'request' value, which will create a new instance of this bean for each HTTP request coming in.
I will also suggest taking a look at the <aop:scoped-proxy/> element for configuration. It is mentioned a couple times in the documentation, and may be useful for what you are trying to do.

This approach will get you into a lot of trouble. Instead of injecting a Session, which you now automatically scopes as a singleton, you should inject the SessionFactory instead. Instances of Session acquired within a #Transactional annotated method will adhere to those transaction rules, eg:
#Transactional(readonly=true)
public List<Person> getPersons() {
Session session = sessionFactory.getCurrentSession();
//find those darn people.
}
#Autowired
private SessionFactory sessionFactory;

Related

Getting null session in spring startup class

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 ?

JSF 2 Spring XRebel Huge session

I recently installed the XRebel plugin, which allows you to see current session size.
I discovered, that the session instantly gets to 10 mb on first page load(initialization of the auth session bean.).
To my setup:
I am using JSF 2.2, Spring 4 and Hibernate 4.
DAO Layer > Service Layer > Managed Bean
DAO Layer
#Named
#Singleton
#Repository
public class UserDao extends BaseDao<User>
{
...
}
Service Layer
#Service
#Named
#Singleton
public class UserService extends BaseService<User>
{
#Autowired
private UserDao dao;
...
}
My auth session bean, that gets loaded on first page load
#Named
#Component
#Scope("session")
public class Auth implements Serializable
{
#Autowired
private UserService userService;
...
}
In my applicationContext.xml I am using
<context:component-scan base-package="com.mypackage" />
This is a general issue I have when I autowire service beans in my session beans.
The Userservice only contains methods to retreive, save and delete user objects, there is no ArrayList containing users or anything else.
I have two #Autowired Services in my auth bean - UserService and SessionService.
If I commment out UserService, SessionService will reach the same size. If I comment out both there is a "DestructionCallbackBindingListener" from "org.springframework.web.context.request.ServletRequestAttribute..." that reaches 8mb instantly.
What am I doing wrong? How do I decrease the session size ?
I gladly accept any help.
Here is an image of XRebel showing that the userService takes about 8mb size in session. http://i.stack.imgur.com/TBXx3.png
Looking at XRebel, it seems that the beanFactory is saved in the user session.
I posted in the official forums regarding XRebel. This is the answer I received.
Indeed, the beanFactory is reachable from the session, through the
CGLIB proxy. We may need to improve to how we recognize objects that
are shared or should not be considered part of the session.
We try to show how much memory each session takes, but Spring
beanFactories are of course shared between sessions usually.
Often the fact that we filter out transient fields from the session
is enough, but we’ll take a look at the CGLIB/Spring proxies to see
how we can filter them out by a general rule or maybe we can just add
specific Spring classes to an ignore list.
In short: The beanfactory can be Ignored when looking at session size, optionally, if possible mark the autowired services transient.
Indeed you can ignore it mentally for now or if it’s possible then
yes, making the variables transient would exclude them.

how can i obtain TransactionManager on WebSphere 8.0?

I tried to obtain the TransactionManager in a #Singleton SessionBean - EJB 3.1 - to control the scope of my transaction, because i have to access a database on a #PostConstruct method. If an exception occurrs, I cannot let the Container RollBack because it throws the TransactionRolledbackException: setRollbackOnly called from within a singleton post construct method.
I am using a JTA DataSource and defined the #TransactionManagement(TransactionManagementType.BEAN) to override control of the transaction.
#Resource
private TransactionManager transactionManager;
returns to me a NullPointerException when i try to do a "transactionManager.begin();". Does anyone knows how to solve this ?
UPDATE:
the code i am using is this:
#Startup
#Singleton
#TransactionManagement(TransactionManagementType.BEAN)
public class RuntimeContextEJB
{
#EJB
private RepositoryRecursosExternosFactoryEJB repositoryRecursosExternosFactoryEJB;
#EJB
private MetodologiaIndiceLiquidezFactoryEJB metodologiaIndiceLiquidezFactoryEJB;
#EJB
private FuncaoMatematicaFactoryEJB funcaoMatematicaFactoryEJB;
private boolean bootstrapRunning = false;
private List<String> dadosMercadoMonitorados;
#PersistenceContext(unitName = "crv-persistence-unit")
private EntityManager entityManager;
#Resource
private TransactionManager transactionManager;
#PostConstruct
public void init()
{
// comentário
MotorCalculoContext.setupMotorCalculoContext(repositoryRecursosExternosFactoryEJB, metodologiaIndiceLiquidezFactoryEJB,
funcaoMatematicaFactoryEJB);
carregaDadosMercadoMonitorados();
}
public void sinalizarInicioBootstrap()
{
bootstrapRunning = true;
}
public void sinalizarTerminoBootstrap()
{
bootstrapRunning = false;
}
public boolean isBootstrapRunnnig()
{
return bootstrapRunning;
}
public void carregaDadosMercadoMonitorados()
{
try
{
transactionManager.begin();
this.dadosMercadoMonitorados = (List<String>) entityManager
.createQuery(
"SELECT DISTINCT(p.parametro.codigoDadoMercado) FROM PlanoExecucaoPasso p WHERE p.parametro.codigoDadoMercado <> '' AND p.parametro.codigoDadoMercado <> '0'")
.getResultList();
}
catch (Exception e)
{
}
}
}
I think there should be a JNDI adress to add on the #Resource annotation, one that is specific for WebSphere, but i really can't find wich is.
UPDATE:
why use JNDI on a container managed injection ? Since i am getting a nullpointer exception from a direct injection, tried to use like the ex. on page 305 from OReilly Enterprise Java Beans 3.1 6th edition.
#Resource(mappedName = "java:/TransactionManager")
//mappedName is vendor-specific, and in this case points to an address in JNDI
tried this with no success.
UPDATE
WebSphere is not getting our beans annotations - can't really know why - so the annotation:
#TransactionManagement(TransactionManagementType.BEAN)
was not working. So, edited de ejb-jar.xml and added the following code:
<transaction-type>Bean</transaction-type>
and the UserTransaction worked. Thanks for the answers.
When you have bean managed transaction, you don't use javax.transaction.TransactionManager but instead you use javax.transaction.UserTransaction.
And then you call begin, commit .... etc of UserTransaction interface.
Answer Updated:
1) First of all, as I said, don't use TransactionManager. Use UserTransaction
2) As you wanted to know the JNDI name of the UserTransaction object. It is java:comp/UserTransaction. But you need this only when your component is not managed. ie: Servlet, EJB. That process is called making a manual call to JNDI API
3) Provide commit() or rollback(). None of them is present.
I am looking at your class and it seems alright.
So, where is the problem ? (possibilities)
1) Your class is not treated as EJB (container managed) and which is why injection fails.
2) Transaction service is not started before EJB #Startup or it fails to start.
3) You have JTA Datasource configured in your persistence.xml. In which case, try:
#Resource
private EJBContext context;
userTransaction = context.getUserTransaction();
Note: Please also provide full stack trace and persistence.xml in order to pinpoint exact problem.
You don't need to use the Transaction Manager in programmatic (BMT) session beans, unless you want to suspend() or resume() the associated transaction in some cases, use the UserTransaction instead .
However, you can get a reference to the Transaction Manager in websphere by com.ibm.ws.Transaction.TransactionManagerFactory class using the static method getTransactionManager() .
public TransactionManager getTransactionManager() {
return TransactionManagerFactory.getTransactionManager();
}
Here's some sample code that runs properly using UserTransaction to have control over transactions.
#Singleton
#Startup
#TransactionManagement(TransactionManagementType.BEAN)
public class SampleUT {
Logger logger = Logger.getLogger(SampleUT.class.getName());
#Resource
private UserTransaction ut;
#PostConstruct
public void postConstruct()
{
logger.info("PostConstruct called");
try {
ut.begin();
...
The NullPointerException you're getting is probably related to you trying to use the injected resource inside the Constructor of your EJB. You should be aware that the injected reference is never available until the constructor of the EJB is finished, so if you try to use any injected reference inside the constructor, it will throw a NullPointerException.

How to inject spring injection manually if not done automatically

My spring dependencies are working fine but there one class
CustomUserDetaisls where i need the Autowired dependency called
#Autowired Private UserDAO userDAO
to match with username and password
But my spring injection is not working here as this class implements the userDetailsSerivce . However injection works if i remove the implements.
I have submitted the question to ask why in this question, but no one gave me answer so i decided to use the DAO with new operator
private UserDAO userDAO = new UserDAO();
But that userDAO in turn depends on session Factory which is a spring bean.
Then i again decided to get sessionfactory from java code rather than spring using following code
SessionFactory sessionFactory = new AnnotationConfiguration()
.configure("com/vaannila/service/hibernate.cfg.xml")
.buildSessionFactory();
But again i have several bean in hibernate-context like datasource , properties file and i am finding it very hard to re-write all the things.
Is there any way that I can manually inject userDAO so that all the related spring injection like sessionFactories works
If you have access to the spring context, you can retrieve an AutowireCapableBeanFactory which you can then use on any bean like this:
ApplicationContext springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContextEvent.getServletContext());
AutowireCapableBeanFactory factory = springContext.get(AutowireCapableBeanFactory.class);
// this would instantiate and autowire a bean:
UserDAO userDAO = factory.createBean(UserDAO.class);
// this will autowire an already existing bean:
UserDAO manualUserDAO = new UserDAO();
factory.initializeBean(manualUserDAO, "beanNameIfNeeded");
However, if a bean requires that it be autowired before it can be used, I prefer to use the first mechanism and mark the constructor as private/protected to make sure that it cannot be created via 'new' and force it to be created via a factory like above.
UPDATE 11/27/17
I personally didn't like to have to use the factory every time I wanted to create an autowired instance. Particularly if some other process was creating the instance, such as deserializing from a database, etc.
I ended up creating a aspect to automatically handle the autowiring.
First, I created an annotation to flag classes that I wanted automatically autowired:
#Documented
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Inherited
public #interface AutowireAfterCreation {
}
Then I created an aspect that uses an 'after construction' point cut to do the autowiring. Unfortunately, I was unable to figure out a point cut that was only called after the 'last' constructor was finished, but it doesn't seem to hurt to autowire multiple times, at least in my case.
public aspect AutowiringAfterCreation {
#Autowired
private AutowireCapableBeanFactory beanFactory;
/**
* After construction, autowire the instance.
* #param o Newly created object to be autowired.
*/
after(Object o) returning : target(o) && initialization((#AutowireAfterCreation *).new(..)) {
// this aspect will actually autowire the instance multiple times if the class is part of an inheritance
// Hierarchy. This is not optimal, but it should not hurt anything to autowire more than once.
// FUTURE: modify the aspect so it only runs once, regardless of how many constructor calls are necessary.
beanFactory.autowireBeanProperties(o, AutowireCapableBeanFactory.AUTOWIRE_NO, false);
beanFactory.initializeBean(o, "unused");
}
}
Then I had to tell Spring about the aspect so the factoryBean is autowired into the aspect itself:
<bean class="AutowiringOnDemand" factory-method="aspectOf"/>
Now I can create any instance and have it automatically autowired simply by attaching the annotation:
#AutowireAfterCreation
public class TestEntity {
#Value("${some.config.value}")
private String value;
#Autowired
private TestRepository repository;
}
Finally, all you have to do is create an instance, and it is automatically autowired after the completion of the constructors:
TestEntity entity = new TestEntity();
UPDATE 1/2/2018
The interface ApplicationContext has changed, and get() has been removed, but you can still use the first mechanism, but you need to call getAutowireCapableBeanFactory() instead.
So the first two lines in the example at the top for this answer would now look like:
ApplicationContext springContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContextEvent.getServletContext());
AutowireCapableBeanFactory factory = springContext.getAutowireCapableBeanFactory();
You can take a look at spring java configuration.
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-java
In example below all dependencies of UserDAO will be automatically set by spring.
It should be something like this:
#Configuration
#PropertySource("classpath:configuration.properties")
public class ApplicationConfig {
#Bean
public UserDAO userDAO() {
return new UserDAO();
}
#Bean
public CustomUserDetails customUserDetails (UserDAO userDAO) {
CustomUserDetails customUserDetails = new CustomUserDetails ();
customUserDetails.setUserDAO(userDAO());
return customUserDetails;
}
}

#PostConstruct and "No Hibernate Session bound to thread" exception

I have to do some database stuff in my repository' #PostConstruct:
#Repository
public class SomeRepositoryHibernate implements SomeRepository {
private SessionFactory sessionFactory;
#Autowired
public SomeRepositoryHibernate(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
...
#PostConstruct
public void doSomestuffWithDb() {
...
}
}
but it fails with:
org.hibernate.HibernateException: No Hibernate Session bound to thread, and
configuration does not allow creation of non-transactional one here
is there any easy solution for that?
Thanks!
You don't have a running transaction in #PostConstruct
you can't use #Transactional there (except for mode="aspectj"), so spring can't start the transaction
a transaction is required for hibernate to mutate data (insert/update/delete)
So, you would have to create your session from the session factory (via .openSession()) there and start a transaction manually.
assuming you are using hibernate combining with spring and you have configured your sessionFactory and transaction manager correctly in your spring config file.
Then the root cause is that when your doSomestuffWithDb() method is invoked the transaction prepare work has not been finished by spring. The #postconstruct can only ensure the method is called after the bean is created, it can not ensure the container is ready for everything- here, I mean the transaction related stuff- at the moment.
There is a detailed discussion in spring forum.
http://forum.springsource.org/showthread.php?58337-No-transaction-in-transactional-service-called-from-PostConstruct
Also, the author submitted his solution to jira at
https://jira.springsource.org/browse/SPR-5966?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel#issue-tabs

Categories

Resources