CDI 1.1 - Inject Dependent scope in ApplicationScope - java

Say I have an #ApplicationScoped service class.
#ApplicationScoped
class MyCustomerService {
...
}
I then want to inject a Connection object into that service.
#ApplicationScoped
class MyCustomerService {
private final Connection connection;
#Inject
MyCustomerService(final Connection connection) {
this.connection = connection;
}
...
}
The Connection object is produced by a #Produces method, using a DataSource.
class ConnectionProducer {
...
#Produces
Connection getConnection(final DataSource dataSource) {
return dataSource.getConnection();
}
...
}
Will the Connection class be proxied? Will CDI invoke the producer method each time I use the connection bean (not like RequestScoped, I really mean for each invocation)?
I know I could just #Inject the DataSource, this is just "learning" how CDI manages scopes.

Will CDI invoke the producer method each time I use the connection bean
No. the producer method called once because the default scope is Dependent . your connection lifecyle bounded to MyCustomerService lifecycle
Will the Connection class be proxied
If the bean is in #Dependent scope, then the client holds a direct reference to its instance(clientproxy is just created for NormalScope)
but if the bean has decorator or interceptor a proxy will be created(client proxy is not created because there is not any context for selecting bean but another proxy is created for applying decorators and interceptors) I tested this at weblogic application server

Related

Spring Boot. Get bean as response to local bean method call

I work on #Configuration class and masterTransactionManager bean needs to be injected with masterDataSource bean. I found example https://www.codeday.top/2017/07/08/31074.html and it not works.
Here simplified example class
#Configuration
public class MasterDataSourceConfig {
#Bean
#Primary
public DataSource masterDataSource() {
DruidDataSource dataSource = new DruidDataSource();
...
return dataSource;
}
#Bean
#Primary
public DataSourceTransactionManager masterTransactionManager() {
/*
* Spring not injects bean here, instead
* it just get new instance
* of DataSource object
*/
return new DataSourceTransactionManager(masterDataSource());
}
}
I was able to fix this with passing bean reference as argument:
#Bean
#Primary
public DataSourceTransactionManager masterTransactionManager(
#Qualifier("schmodelAuditDataSource") DataSource dataSource) {
/*
* Now bean injected, and everything works as it should
*/
return new DataSourceTransactionManager(dataSource);
}
Now the question is: how could it work new DataSourceTransactionManager(masterDataSource())? I never saw before that Spring can return bean on method call like in first example. Is this proper solution to get the bean? If this proper call, then why it not works for me?
I was not able to find a lot about such bean call method, though in thread Spring boot bean into bean injection methodology mentioned it should work. While in my case it is not.
Update: what error I see
The error I get in first case is
Error querying database. Cause: org.springframework.jdbc.CannotGetJdbcConnectionException
also in debug mode I see the instance of bean on spring bean initiation call is different, from the returning when my class calls masterDataSource() method.
The application starts without errors. I get error when start using beans instantiated (write data to database). I think this is result of not proper bean (is it bean at all, not sure) returned when called masterDataSource()
Before answer the question I need to clear what is Autowiring?
Spring managed their bean and lifecycle inside application context which is a container. Application context is a container which contain bean.
When the application context bootstrapped the beans also instantiated by their defined scope (singleton, prototype, request, session, global-session).
Spring's default scope is singleton refers it instantiate at once and shared the object (usually a cached object) within application context.
Autowire happens inject a beans instance to another bean.It means where we inject and what we inject -- both should be beans and lived in Spring IoC container (Application Context).
Now come to you question. If you autowire a bean, in fact your instantiated object (instantiated by spring) is set here.If you call some method like masterDataSource() in your example:-
#Bean
#Primary
public DataSource masterDataSource() {
DruidDataSource dataSource = new DruidDataSource();
...
return dataSource;
}
#Bean
#Primary
public DataSourceTransactionManager masterTransactionManager() {
return new DataSourceTransactionManager(masterDataSource());
}
Then masterDataSource() also create a new object and set (Injected) to DataSourceTransactionManager constructor.
So bottom line is if you used #Autowired then you get spring managed (lifecycle) bean/object and if you called masterDataSource() then you just create a new object apart from spring managed object.

Accessing stateless EJBs in PreDestroy method of Singleton

I have a problem accessing stateless EJBs in the preDestroy method of an singleton. I need to log the shutdown of the application server in an database table.
This is what the singleton looks like:
#Startup
#Singleton
public class ServerShutdown {
#EJB
TableFacade tableFacade;
#PreDestroy
private void shutdown() {
TestEntity e = tableFacade.find("test");
//do something
}
}
Here's example code of the stateless bean:
#Stateless
public class TableFacade {
...
public TestEntity find(String test) {
Query query =
getEntityManager().createNamedQuery("TestEntity.namedQuery");
return (TestEntity) query.getSingleResult();
}
}
If the server is shutting down, the preDestroy method is accessed and the EJB method is called. But during the call, the server seems to force the shutdown process and cancels the calling of the EJB method.
I'm using Java EE 6, JDK 1.8, EJB 3.1, eclipselink 2.5.2.
Thanks in advance
The #predestroy should only do ejb resource cleanup, such as connection, variable etc...
Your problem has to do with the transaction context, infact from the spec:
The PreDestroy lifecycle callback interceptor methods for stateless
and stateful session beans execute in an unspecified transaction
context.
And then:
For example, it would be wrong to perform database operations within a
stateful session bean’s PostConstruct or PreDestroy lifecycle callback
interceptor methods and to assume that the operations are part of the
client’s transaction. The PostConstruct and PreDestroy methods for
stateful and stateless session beans are not controlled by a
transaction attribute because handling rollbacks in these methods
would greatly complicate the session instance’s state diagram.
So, it is not explicitly forbidden, but you are warned that things may go wrong.
According to the ejb 3.2 spec, singleton beans are allowed to access ejb's in their pre destroy method. See section 4.8.6 Table 3. If a singleton bean needs to access another singleton bean, then it must declare its dependency using the #DependsOn annotation. The example provided by the original poster should work.

Spring JdbcTemplate alter session

I want to alter Oracle session for every connection that I get from the connection pool.
I found that it can be done by simply execute a statement. See here.
Is there a way to hook into the jdbc template or the datasource and execute a statement after the connection pool creates a new connection.
I'm using Spring Boot and creating the datasource that way:
#Bean
#ConfigurationProperties(prefix="datasource.local")
public DataSource localDataSource() {
return DataSourceBuilder.create().build();
}
There are a lot of ways to do so.
The first one:
DataSource is an interface, so why don't you implement it yourself (use Proxy pattern)? Create something like this:
class MyDataSource implements DataSource {
private DataSource realDataSource;
public Connection getConnection() {
Connection c = realDataSource.getConnection();
// do whatever you want to do and
return c;
}
}
All other methods will delegate directly to realDataSource.
This proxy can be used in a provided code snippet.
You can use some AOP - just provide an advice that after get connection is created will run and do whatever you need there. Basically it's the same proxy but automatically created by Spring.

Getting a reference to EntityManager in Java EE applications using CDI

I'm using Java EE 7. I would like to know what is the proper way to inject a JPA EntityManager into an application scoped CDI bean. You can't just inject it using #PersistanceContext annotation, because EntityManager instances are not thread safe. Let's assume that we want our EntityManager to be created at the beginnig of every HTTP request processing and closed after the HTTP request is processed. Two options come into my mind:
1.
Create a request scoped CDI bean which has a reference to an EntityManager and then inject the bean into an application scoped CDI bean.
import javax.enterprise.context.RequestScoped;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
#RequestScoped
public class RequestScopedBean {
#PersistenceContext
private EntityManager entityManager;
public EntityManager getEntityManager() {
return entityManager;
}
}
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
#ApplicationScoped
public class ApplicationScopedBean {
#Inject
private RequestScopedBean requestScopedBean;
public void persistEntity(Object entity) {
requestScopedBean.getEntityManager().persist(entity);
}
}
In this example an EntityManager will be created when the RequestScopedBean is created, and will be closed when the RequestScopedBean is destroyed. Now I could move the injection to some abstract class to remove it from the ApplicationScopedBean.
2.
Create a producer that produces instances of EntityManager, and then inject the EntityManager instance into an application scoped CDI bean.
import javax.enterprise.context.RequestScoped;
import javax.enterprise.inject.Produces;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
public class EntityManagerProducer {
#PersistenceContext
#Produces
#RequestScoped
private EntityManager entityManager;
}
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.persistence.EntityManager;
#ApplicationScoped
public class ApplicationScopedBean {
#Inject
private EntityManager entityManager;
public void persistEntity(Object entity) {
entityManager.persist(entity);
}
}
In this example we will also have an EntityManager which is created every HTTP request, but what about closing the EntityManager? Will it also be closed after the HTTP request is processed? I know that the #PersistanceContext annotation injects container-managed EntityManager. This means that an EntityManager will be closed when a client bean is destroyed. What is a client bean in this situation? Is it the ApplicationScopedBean, which will never be destroyed until the application stops, or is it the EntityManagerProducer? Any advices?
I know I could use a stateless EJB instead of application scoped bean and then just inject EntityManager by #PersistanceContext annotation, but that's not the point :)
You're almost right on with your CDI producer. Only thing is that you should use a producer method instead of a producer field.
If you're using Weld as CDI container (GlassFish 4.1 and WildFly 8.2.0), then your example of combining #Produces, #PersistenceContext and #RequestScoped on a producer field should throw this exception during deployment:
org.jboss.weld.exceptions.DefinitionException: WELD-001502:
Resource producer field [Resource Producer Field [EntityManager] with
qualifiers [#Any #Default] declared as [[BackedAnnotatedField]
#Produces #RequestScoped #PersistenceContext
com.somepackage.EntityManagerProducer.entityManager]] must be
#Dependent scoped
Turns out that the container is not required to support any other scope than #Dependent when using a producer field to lookup Java EE resources.
CDI 1.2, section 3.7. Resources:
The container is not required to support resources with scope other
than #Dependent. Portable applications should not define resources
with any scope other than #Dependent.
This quote was all about producer fields. Using a producer method to lookup a resource is totally legit:
public class EntityManagerProducer {
#PersistenceContext
private EntityManager em;
#Produces
#RequestScoped
public EntityManager getEntityManager() {
return em;
}
}
First, the container will instantiate the producer and a container-managed entity manager reference will be injected into the em field. Then the container will call your producer method and wrap what he returns in a request scoped CDI proxy. This CDI proxy is what your client code get when using #Inject. Because the producer class is #Dependent (default), the underlying container-managed entity manager reference will not be shared by any other CDI proxies produced. Every time another request want the entity manager, a new instance of the producer class will be instantiated and a new entity manager reference will be injected into the producer which in turn is wrapped in a new CDI proxy.
To be technically correct, the underlying and unnamed container who do the resource injection into the field em is allowed to reuse old entity managers (see footnote in JPA 2.1 specification, section "7.9.1 Container Responsibilities", page 357). But so far, we honor the programming model required by JPA.
In the preceding example, it would not matter if you mark EntityManagerProducer #Dependent or #RequestScoped. Using #Dependent is semantically more correct. But if you put a wider scope than request scope on the producer class you risk exposing the underlying entity manager reference to many threads which we both know is not a good thing to do. The underlying entity manager implementation is probably a thread-local object, but portable applications cannot rely on implementation details.
CDI does not know how to close whatever stuff it is that you put into the request bound context. More so than anything else, a container-managed entity manager must not be closed by application code.
JPA 2.1, section "7.9.1 Container Responsibilities":
The container must throw the IllegalStateException if the application
calls EntityManager.close on a container-managed entity manager.
Unfortunately, many people do use a #Disposes method to close the container-managed entity manager. Who can blame them when the official Java EE 7 tutorial provided by Oracle as well as the CDI specification itself use a disposer to close a container-managed entity manager. This is simply wrong and the call to EntityManager.close() will throw a IllegalStateException no matter where you put that call, in a disposer method or somewhere else. The Oracle example is the biggest sinner of the two by declaring the producer class to be a #javax.inject.Singleton. As we learned, this risk exposing the underlying entity manager reference to many different threads.
It has been proven here that by using CDI producers and disposers wrongfully, 1) the not thread-safe entity manager may be leaked to many threads and 2) the disposer has no effect; leaving the entity manager open. What happened was the IllegalStateException which the container swallowed leaving no trace of it (a mysterious log entry is made which says there was an "error destroying an instance").
Generally, using CDI to lookup container-managed entity managers is not a good idea. The application is most likely better off just using #PersistenceContext and be happy with it. But there are always exceptions to the rule like in your example, and CDI can also be useful to abstract away the EntityManagerFactory when handling the life cycle of application-managed entity managers.
To get a complete picture on how to obtain a container-managed entity manager and how to use CDI to lookup entity managers, you might want to read this and this.
I understand your problem. but that is not a real one. Do not get messed up with the CDI declared scope of a containing class, that will propagate the scope of the attributes expect those that use #Inject'ion!
The #Inject'ed will compute their reference in depencency of the CDI-declaration of the implementation class. So you might have Applicationscoped class with a #Inject EntityManager em inside, but each controlflow will find its own em-transaction reference to a disjount em-object, because of the EntityManager CDI declaration of the implementation class behind.
The wrong thing of your code is, that you provide an inner getEntityManager() access method. Do not pass Injected object, if you need one, simply #Inject it .
You should use the #Dispose annotation to close the EntityManager, as in the example below:
#ApplicationScoped
public class Resources {
#PersistenceUnit
private EntityManagerFactory entityManagerFactory;
#Produces
#Default
#RequestScoped
public EntityManager create() {
return this.entityManagerFactory.createEntityManager();
}
public void dispose(#Disposes #Default EntityManager entityManager) {
if (entityManager.isOpen()) {
entityManager.close();
}
}
}
You may inject savely EntityManagerFactory, it is thread save
#PersistenceUnit(unitName = "myUnit")
private EntityManagerFactory entityManagerFactory;
then you can retrive EntityManager from entityManagerFactory.

Configuring DAO factory with Pooled DataSource

I'm after a bit of advice regarding configuring a DAO factory with a pooled datasource. Suppose its a JDBC DAO factory (from an abstract factory) and the pooled datasource is configured and managed by the application server e.g. Glassfish
When the factory is created for the first time (Singleton pattern) it does a JNDI lookup for the pooled datasource e.g. from a properties file, which will set the pooled datasource on the JDBC DAO factory.
Then, when you instantiate and return the concrete DAO would you pass it a reference to datasource so it could retrieve a connection to the database?
Basically what I did was encapsulate that datasource as a field in a base class called DAO. In the constructor of the DAO you pass in the JNDI name of the connection you want.
public DAO(String jndiName) throws NamingException {
ds = DataSourceFactory.getInstance().lookup(jndiName);
}
Then in all of your concrete classes you simply extend from DAO and can use the datasource as you want.
public concreteDAO() throws NamingException {
super("Some JNDI Name That this DAO should know");
}
The same DAO class has some other utility methods like a cleanup method, that silently closes the ResultSet, Statements and Connections. So that way I just have to add this in the finally clause of all my methods.

Categories