Which is the best approach to implement several different databases in one project, using Spring JdbcDaoSupport?
I have several DB with different datasources and syntax: MySQL & Postgres, for example. In pure java-jdbc projects i used Factory Method and Abstract Factory patterns, and multiple DAOimpl classes (one for each DB) with common DAO interfaces for switch between databases. Now i use Spring-jdbc and want to implement similar behavior.
I faced the same matter two year ago and I finally choose an implementation based on a "Spring Custom Scope" (http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-scopes-custom).
The spring frameworks allows multiple instances of the same bean definition to coexists together. They differ only from some contextual settings.
For instance, this bean definition will create various loginAction bean depending on the currently processed HTTP request
<bean id="loginAction" class="com.foo.LoginAction" scope="request"/>
If you create a custom scope called "domain", you will be able to instanciate several datasource based on the same bean definition.
A datasource bean definition based on JndiObjectFactoryBean would let the servlet container manage the database connection (through the web.xml file). However, you would have to variabilize your datasource name with a Spring Property.
Beans like the database Transaction Manager must also be marked with this scope.
Next you need to activate the scope each time an HTTP request is running: I can suggest you to define the datasource name as a prefix of the request url.
Because most of web frameworks allows you to intercept HTTP requests, you can retrieve the expected datasource before processing the request.
Then, create (or reuse) a set of beans specific to the selected datasource and store it inside a ThreadLocal variable (that your custom scope implementation will rely on)
This implementation should look a little complex at first glance, but its usage appears transparent.
Related
We're using Spring Boot 1.5.10 with Spring Data for Apache Cassandra and that's all working well.
We've had a new requirement coming along where we need to connect to a different keyspace while the service is up and running.
Through the use of Spring Cloud Config Server, we can easily set the value of spring.data.cassandra.keyspace-name, however, we're not certain if there's a way that we can dynamically switch (force) the service to use this new keyspace without having to restart if first?
Any ideas or suggestions?
Using #RefreshScope with properties/repositories doesn't work as the keyspace is bound to the Cassandra Session bean.
Using Spring Data Cassandra 1.5 with Spring Boot 1.5 you have at least two options:
Declare a #RefreshScope CassandraSessionFactoryBean, see also CassandraDataAutoConfiguration. This will interrupt all Cassandra operations upon refresh and re-create all dependant beans.
Listen to RefreshScopeRefreshedEvent and change the keyspace via USE my-new-keyspace;. This approach is less invasive and doesn't interrupt running queries. You'd basically use an event listener.
#Component
class MySessionRefresh {
private final Session session;
private final Environment environment;
// omitted constructors for brevity
#EventListener
#Order(Ordered.LOWEST_PRECEDENCE)
public void handle(RefreshScopeRefreshedEvent event) {
String keyspace = environment.getProperty("spring.data.cassandra.keyspace-name");
session.execute("USE " + keyspace + ";");
}
}
With Spring Data Cassandra 2, we introduced the SessionFactory abstraction providing AbstractRoutingSessionFactory for code-controlled routing of CQL/session calls.
Yes, you can use the #RefreshScope annotation on a the bean(s) holding the spring.data.cassandra.keyspace-name value.
After changing the config value through Spring Cloud Config Server, you have to issue a POST on the /refresh endpoint of your application.
From the Spring cloud documentation:
A Spring #Bean that is marked as #RefreshScope will get special treatment when there is a configuration change. This addresses the problem of stateful beans that only get their configuration injected when they are initialized. For instance if a DataSource has open connections when the database URL is changed via the Environment, we probably want the holders of those connections to be able to complete what they are doing. Then the next time someone borrows a connection from the pool he gets one with the new URL.
From the RefreshScope class javadoc:
A Scope implementation that allows for beans to be refreshed dynamically at runtime (see refresh(String) and refreshAll()). If a bean is refreshed then the next time the bean is accessed (i.e. a method is executed) a new instance is created. All lifecycle methods are applied to the bean instances, so any destruction callbacks that were registered in the bean factory are called when it is refreshed, and then the initialization callbacks are invoked as normal when the new instance is created. A new bean instance is created from the original bean definition, so any externalized content (property placeholders or expressions in string literals) is re-evaluated when it is created.
Env:
Wildfly 8.2.0 Final
JDK 8
Java EE 7
Please note that by 'POJO' i am referring to the classes that serve the other classes i.e other than value objects, entities.
This question was on back of my head for some time. Just wanted to put it out.
Based on CDI and Managed Beans specs and various other books/articles, its pretty clear that CDI injection starts with a 'managed' bean instance. By 'managed' i mean servlet, EJBs etc. which are managed by a container. From there, it injects POJOs (kind of crawl through layers) till every bean gets its dependencies. This all makes very sense to me and i see very little reason why developers ever need to use "new" to create an instance of their dependent POJO's.
One scenario that comes to my mind is when developer would like to have logic similar to
if(something) {
use-heavy-weight-A-instance
} else {
use-heavy-weight-B-instance
}
But, that also can be achieved via #Produces.
Here is one scenario that i verified to be true in wildfly 8.2.0 Final i.e. CDI is not able to inject bean when the JSP has
<%!
#Inject
BeanIntf bean;
%>
But, the alternative to use a servlet works fine.
That said, would like to know if there is any scenario(s) where a developer has to use 'new'. As i understand, by using 'new', developer owns the responsibility of fulfilling dependencies into that bean and all its dependent beans, and their dependent beans etc..
Thanks in advance,
Rakesh
When using CDI or other container you don't use new, because you expect a bunch of service coming from the container.
For CDI these main services are:
Injection of dependent beans (get existing instance or create a new
instance)
Lifecycle callback management (#PostConstruct and
#PreDestroy)
Lifecycle management of your instance (a #RequestScoped bean will make container produce an instance leaving until the end of request)
Applying interceptors and decorators on your instance
Registering and managing observers methods
Registering and managing producers methods
Now, on some rare occasion, you may want to add a part of these services to a class you instantiate yourself (or that another framework like JPA instantiate for you).
BeanManager bm = CDI.current().getBeanManager();
AnnotatedType<MyClass> type = bm.createAnnotatedType(MyClass.class);
InjectionTarget<MyClass> it = bm.getInjectionTargetFactory(type).createInjectionTarget(null);
CreationalContext<MyClass> ctx = bm.createCreationalContext(null);
MyClass pojo = new MyClass();
injectionTarget.inject(instance, ctx); // will try to satisfied injection points
injectionTarget.postConstruct(instance); // will call #PostConstruct
With this code you can instantiate your own MyClass containing injection points (#Inject) and lifecycle callbacks (#PostConstruct) and having these two services honored by the container.
This feature is used by 3rd party frameworks needing a basic integration with CDI.
The Unmanaged class handle this for you, but still prevent you to do the instantiation ;).
I am studying Spring MVC and I have the following doubts:
What exactly is the purpose of the session scope?
Reading the documentation I know that this scopes a bean definition to an HTTP session. Only valid in the context of a web-aware Spring ApplicationContext. And also that a new instance is created once per user session.
But when exactly is it used? and for what purpose? Can you make a practical example?
In Spring MVC what is the default scope in the web context?
I know that in Spring the default scope for a bean is singleton but what about the scope of a bean in the web context?
Ans 1) session scope is very similar to HttpSession scope. Beans instantiated based on session scope scope lives through the HTTP session. Similar to request scope, it is applicable only for web aware spring application contexts.
/** * Annotation-based configuration of session scope */
#Component
#Scope("session")
public class ShopCart { }
and then
#Inject
private ShopCart cart;
Ans 2) Default is Singleton everywhere.
You use spring session beans for beans which are stateful and their state differs per user. These can be for example preferences of currently logged in user.
Default scope of bean in spring is singleton and it is no different in Web Application context.
Note than in web environment you can use also REQUEST scoped beans and their lifetime is only per one user request. You should use request scope when session is not necessary and request is sufficient.
Also, in portlet environment, you can use another scope which is GLOBAL SESSION. Each portlet has its own indepenednt session and typically those portlets are preffered to have their own state encapsulated only for themselves. But if you need to share session data among different portlets, you will need to use global session scope.
Actually Spring help you create Session scope bean instead traditional way
httpSession.setAttribute("Object",new Object());
&&
httpSession.getAttribute("Object");
and Spring provide this efficient way
#Component
#Scope("session")
public class Foo{
}
now it's headache of spring to create and destroy this associated session object using Factory Pattern
I had the same problem, I was using:
#Component
#Scope("session")
And this made the magic for me:
#Component
#Scope(value = "session", proxyMode = ScopedProxyMode.TARGET_CLASS)
I hope it helps ;-)
But when exactly is it used? and for what purpose? Can you make a
practical example?
In one of my JSP based Spring MVC web apps, we use it to store data that doesn't vary after user's first request in the session i.e. we populate fields of this bean when user first comes to server & then we use ( aka read ) these values in subsequent requests ( next requests in session ) e.g. user name, user org group, address , logged in client number etc etc.
These constants values are kind of mandatory & be needed in all log messages or in all SQL queries.
Request routing is designed in such a way that bean population ( setting of bean properties ) happens only once per session.
Other interesting part as pointed in Yasir Shabbir Choudhary's answer that you can mimic same behavior using traditional way.
Is Spring session scoped bean saved in HttpSession?
Your second question is already answered by many that default scope - Singleton is applicable here too.
I have a data structure representing a CSV file containing thousands of config settings. The structure is a Java class file with instance variables to represent the records in the file (ie: a HashMap) and the state of the file (errors, warnings, etc).
These classes are not created by Spring as they have state. I would like the class to access system configuration properties which are currently handled by a Spring managed database DAO class. Usually when classes need this DAO I inject it through Spring using #Autowired. But as my data structure is not managed by Spring, how can the CSV structure class access the DAO?
The only method I can think of is when creating the data structure from the Spring managed bean to just pass in the DAO:
CSVDataStruture c = new CSVDataStruture(dao);
See 6.8.1. Using AspectJ to dependency inject domain objects with Spring about using #Configurable
Another way is to get ahold of the application context (in web applications this is WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext)) and get the beans using context.getBean("name"), but it is more of a workaround.
These classes are not created by Spring as they have state.
What makes you think that Spring cannot / should not create objects that have state?
Depending on what you are trying to do (it is hard to figure this out!) I would do one of the following:
Give the CSV class getters and setters for a CVS file parameter and a DAO parameter, and instantiate it using Spring DI. This assumes that the filename is available when Spring wiring occurs.
Create a factory class with a method that instantiates a CSV object from a file parameter. The factory class should have a getter/setter for the DAO object and be instantiated using Spring DI.
I wrote a custom Struts RequsetProcessor for my application that is manually fetching some references from Spring. It is working just fine, but I would like to do the "right" thing and inject everything I need at construction time.
Is there a way to define a custom Struts RequestProcessor in a way that I can inject Spring objects into it when Struts instantiates this RequestProcessor?
The short answer is "NO". The long answer is "kind of":
Assuming Struts is integrated with Spring in your application via ContextLoaderPlugin, you can do one of two things:
A) Create a "ProcessorContext" bean (or whatever you want to call it) that you would define in your Spring context and access from your custom request processor by obtaining it from Spring's context (which you can get via WebApplicationContextUtils.getWebApplicationContext(getServletContext())).
B) If your custom processor extends Spring's DelegatingRequestProcessor or DelegatingTilesRequestProcessor you can instead write a new request processor that would do what you want functionality-wise, bind it to Spring context with all your dependencies and then extend DelegatingRequestProcessor or DelegatingTilesRequestProcessor to get it from context (either via type or id) and delegate to it. This is essentially an extension of (A) but it delegates all Spring's plumbing to Spring's request processor extension leaving your custom processor Spring-independent.
Spring / Struts integration is described in detail here.