What is the best method to access Service Layer from Controller in Spring MVC? I'm using annotations for SpringMVC.
Earlier I used to get the bean everytime from the bean factory by calling ClassPathXMLApplicationContext(spring-bean-name.xml) in every method of controller.
From the solution to question Accessing Service Layer from custom Controller in Spring MVC I understand that service bean has to be autowired.
However suppose a controller accesses multiple services do we have to inject multiple beans? But that won't be a good practice cause we will have to use a particular service only in 1-2 methods within a controller and its not good to make it a class variable rather than a function variable.
You are correct, you need to autowire the services you intend to use. Don't worry about class variable versus local (function) variable, this is how the DI pattern is implemented.
In the strictest OO-design sense, you have a point that you should not declare variables on a class-level unless they are involved in describing the state of an object. DI (Dependency Injection) is, however, a very established pattern on no developer is going to frown upon service beans as autowired class members, regardless of how many methods actually use the service.
On a side-note, doing new ClassPathXMLApplicationContext("spring-bean-name.xml") in every method is absolutely, 100% the wrong way to do it. That involves creating a new bean-factory and bean-context every time you execute that method which is a big overhead and completely unnecessary. The bean-factory should be created once (if you're in a servlet-engine environment, by using the DispatcherServlet or the ContextLoaderListener).
You can have a static class which instantiates bean factory and then use custom static getBean method of this static class
static class SpringConfig()
{
private static ApplicationContext ctx = null;
static
{
ctx=new ClassPathXmlApplicationContext("context.xml");
}
public static Object getBean(String beanName)
{
return ctx.getBean(beanName);
}
}
This is why you have to try to keep all the methods that use the same dependencies together, this is low coupling. The bad practice is not injecting your dependencies as global variables. The bad practice is to not group your methods to make your class less coupled.
Related
I'm studying spring beans and came across #Lookup, it says:
If we happen to decide to have a prototype Spring bean, then we are
almost immediately faced with the problem of how will our singleton
Spring beans access these prototype Spring beans?
hmm, I don't get it, because when I studied scope=prototype it says:
4.4.2 The prototype scope
The non-singleton, prototype scope of bean deployment results in the creation of a new bean instance every time a
request for that specific bean is made
so it seems i misinterpreted the words:
a request for that specific bean is made
actually programming in spring framework every line of the code is inside of some bean (i.e. #controller, #Service, etc), isn't it?
And almost all of them are singletons, isn't it?
So if I need prototype I just make scope=prototype and almost everytime it's injected to another bean (i.e. #controller, #Service, etc) isn't it?
So please give a real world scenarios, 1) when one should use #Lookup and 2) when it's not needed
Ok for the 1) the scenario:
#Component
#Scope("prototype")
public class SchoolNotification {
// ... prototype-scoped state
}
#Component
public class StudentServices {
// ... member variables, etc.
#Lookup
public SchoolNotification getNotification() {
return null;
}
// ... getters and setters
}
Please, show me scenario for the 2) case, and explain please the difference
Thank u
The implicit Bean scope in Spring is Singleton.
That means for a JVM instance, only a single instance of a Bean exists in memory (theoretically).
When you #Autowire a Prototype-scoped Bean inside a Singleton-scoped Bean, that Prototype one becomes a sort-of-singleton. Just think about it; a Singleton gets created, its injectable fields get Autowired, and that is it, the instance lives forever along with all its fields (keep in mind those Prototype-scoped fields are "pure" instances, they're not proxied).
#Lookup
is a proxy-driven annotation. What that means is Spring will extend your class using JDK proxies or CGLIB proxies, and it will override/implement the #Lookup-annotated method, providing its own version which uses a BeanFactory#getBean each time it is invoked.
The documentation is clear on this point
An annotation that indicates 'lookup' methods, to be overridden by the
container to redirect them back to the BeanFactory for a getBean call.
Thus, that means a fresh Bean instance is returned every time.
Just for your knowledge, another approach for working with Prototype-scoped Beans inside "other"-scoped Beans is using ProxyFactoryBean. The only difference is that the proxy is created at configuration-time, and then made available for direct #Autowireing, thus not requiring the definition of a #Lookup method, which sometimes is not wanted (usually by folks that are obsessed with clean code, like me).
I'm using WELD SE on a standalone java project which seemed to work fine till I started using producers.
The producer method works - the container uses it, but never injects the inner pdependencies of the produced bean. When I remove the producer, it works normally. I can't find the cause even after a long search on the spec and on Google.
Example of a Producer:
#ApplicationScoped
public class LaminaValidadorProducer {
private static final String XSD_PATH = getConfig("processador.xsd.path");
private static final Map<VersaoLamina,String> XSD_PER_VERSION = new HashMap<>();
static {
XSD_PER_VERSION.put(VersaoLamina.V1, getConfig("processador.lamina.xsd.file"));
XSD_PER_VERSION.put(VersaoLamina.V2, getConfig("processador.laminav2.xsd.file"));
}
#Produces
public LaminaValidador buildValidador() {
return new LaminaValidador(XSD_PATH, XSD_PER_VERSION);
}
}
LaminaValidador is injected normally, but its INNER attributes (marked with #Inject) are not being injected. THe project has a beans.xml with bean-discovery-mode="all".
Any clues on what's happening?
This is not only a matter of SE and it is in fact a desired/expected behaviour of CDI.
The reason behind this is that normally, if you do not have producers, CDI creates the bean classes for you (by calling no-args constructor, or one with injections) and subsequently resolves the injection points within the bean (and does some other things, see spec). E.g. you leave the lifecycle management to CDI container.
On the other hand, using a producer is usually a way to create a bean out of a class where:
you cannot control lifecycle youself, e.g. EntityManager
you intergrate with other frameworks and they have complex initialization
you need to do some checks for external config before calling certain constructor
or you maybe want a bean for a primitive type (int)
and many many more use cases
Now this means you are responsible for the creation of the bean. And that includes any fields within. Container just takes the producer as a way to create a full-blown bean and assumes you took care or what the initialization required.
Now, from your question I judge you need the injection point resolution inside. There is no easy way, if any, to "enforce" the resolution manually due to static nature of CDI (and other, more complex reasons). Hence I would propose to use a different approach and leverage constructor injection or maybe initializer methods? If you provide more information, I might be able to help.
I am new to Spring and read that we can't use #Cacheable with static method but can't found why we can't use so any one can explain so that beginner can understood easily?
Can we use static method for retrieving database table?
I have made static method of all method of service layer of DAO so Is this thread-safe?
Elaborating on my comment:
"Static methods cannot be cached. The way aspects work in Spring is by adding a wrapper class (a proxy) to the annotated class. There is no way in Java to add a wrapper to a static method."
Since Spring needs an object to wrap around in order to intercept calls to that object and perform various operations before delegating the modified input to the original object (thus spring aspects are possible).
Since anything that is static cannot be instantiated as an object, Spring has no way to wrap around it and intercept its calls (at least with the current implementation of Spring)
It is a limitation of the mechanism used to provide caching.
When you mark some method as #Cacheable, Spring creates a proxy to your bean that intercepts method invocations and provides the caching, and will inject that instead of the original bean. So if you have some code like:
#Inject
private MyBean myBean;
...
myBean.myMethod("foo");
where MyBean has declared myMethod() as #Cacheable, then myBean will not point to what you put in the application context, but to a proxy that will do the caching and invoke the original MyBean.myMethod() only when cache lookup does not return anything.
Proxys cannot intercept static methods, so the proxy cannot cache static methods. That is why #Cacheable will not work on static methods.
I know it is not a best design but just a thought from a Spring newbie.
Now we can easily autowire any service method to each other conveniently in Spring framework. But What is the disadvantage to create a static factory method of the service class and call it everywhere?
It's pretty common like this:
#Autowired
CustomerService customerService;
....
AccountDetail ad = customerService.getAccountDetail(accountId, type);
But this should work too:
AccountDetail ad = CustomerService.getAccountDetail(accountId, type); //if we make getAccountDetail(String, String) static
So why there is a design like autowire? It looks fancy and really cool, but the work behind this is still create one service bean instance on another service object.
Seriously while Spring is all over the market so many posts and articles are talking about pros & renovations. But is it guaranteeing better performance(like using autowire instead of static)?
There are numerous reasons:
you can't replace CustomerService with a mock easily during tests (tools like PowerMock aside)
static methods do not participate in standard, proxy-based AOP (no transactions, security, custom aspects)
you can no longer use fancy injection techniques, like injecting HTTP request (request scoped) into singleton scoped services (poor design anyway, but...)
But to be complete, there are also advantages:
static method is actually closer to your intent, Spring beans are very rarely stateful, thus they don't really need an instance to work
static call might be faster (this is irrelevant in 99% of the programs)
What if you need to have multiple CustomerService components with different configuration? You can't do that with a single static method.
Also, if there's any configuration whatsoever on CustomerService, how do you inject it? Having a bean that gets wired into dependent objects centralizes your configuration and keeps you from having to hunt through your code.
I have sucessfully used Guice to Inject Providers into the servlet portion of an existing java web application, however, I can't access the injectors through the business layer (non-servlet java classes) of the application.
I have read up on Injecting the Injector, but to me that seems more like a hack and in several places, including the Guice documentation, it says not to do that too much.
I guess my question is, Where do I bootstrap a java web app so that the non-servlet/filter classes have access to the injector created in the class I use to extend GuiceServletContextListener? Is there any way to make those classes injectable without injecting the injector?
Thank you and let me know if you need any clarification.
Edit:
I am attempting to do this with a simple logger, so far, in my
servlets, I call:
#Inject
private static org.slf4j.Logger log;
The injection is set up in MyLoggerModule as follows (which is in the
createInjector call with ServletModule) :
#Override
public void configure() {
bindListener(Matchers.any(), new SLF4JTypeListener()); // I
built my own SLF4JTypeListener...
}
This all works perfectly in the servlets, but the field injection does
not work when called by a class that is not a servlet or filter.
Guice doesn't intercept calls for new objects, so if your business layer isn't already using Guice to create the objects that need injection, it'll need modification to do so.
The injection only works when handled by Guice during injection. So starting from the base injector you've made, whatever is marked with #Inject which is needed for the instance you've requested will be provided by Guice as best it can, and in turn, during instanciation of those, further #Inject annotations will be filled in by providers and bindings until nothing new needs to be instanciated. From that point on however you are not going to get fields injected into servlets created outside Guice's injection, perhaps by calling new somewhere, which is likely what your Object Factory is doing.
You'll need to change your Object Factory to use providers instead of new. If you could edit these, it wouldn't be too hard to do since Guice can give you default providers for bindings.
So one way your business layer could be Guice aware is to have whatever is creating servlets first create an Injector and then request the servlets be created by the injector. If this means you'll have more than one injector, then yes, that will be a problem but only for the objects you want to be singletons. So you could make a factory pattern class for a singleton injector, or you could find where these classes (here typed bar) which are creating servlets themselves are created (in foo), and then start with the injector there (in foo) using one Guice injector to create those (bar type) classes and also modifying them (bar type) to request a provider for the servlets which they'll use instead of making calls for a new servlet.
Now that I think about this, it could be simple if it kind of only happens once or twice for 10-20 servlet types, or it could be complicated if there's some framework that defines totally flexible behavior for what gets newed up when and why.
Another option would be avoiding #Inject on fields at all times, as recommended. So now your servlets are taking in an org.slf4j.Logger as a construction parameter. The constructor is marked #Inject, and it assigns the parameter's value to the field. Then any place you're not using injection should break with an incorrect number of parameters at a new call. Fix these by figuring out how to either get the servlet provided here instead, or how to get a provider for the servlet into the class.
Not sure what you mean... if you inject objects in to your servlets/filters, those objects have their dependencies injected by Guice as well, and so on all the way down.
How are you creating the classes that you're trying to inject this logger in to? They must be created by Guice to be injected, which means no new.