If i write a simple servlet application, in my servlet class i extend the http servlet. This lets the container know that my class is a servlet and it will manage the 'lifecycle' of the servlet. init, doget(), destroy() etc.
But the Spring MVC framweork controller class does not extend any servlet class. it is jsut a POJO with it s own custom methods. Now I can call those methods individually using Requestmapping.
But will this spring controller class be 'mananged' by the container in a same way a servlet lifecyle is managed?
But will this spring controller class be 'mananged' by the container
in a same way a servlet lifecyle is managed?
Not directly. Then entry point of a Spring MVC application is typically a DispatcherServlet*. This class extends (not directly, but through inheritance) HttpServlet. You declare it as you would any other Servlet, typically in web.xml.
However you don't declare it by itself. You provide a Spring ApplicationContext from which the DispatcherServlet can go and get the #Controller annotated classes it will use to handle requests.
The DispatcherServlet handler stack is pretty big. There are many components involved. The official Spring MVC is an excellent document. You should read it.
*I say typically because Spring provides other handlers, HttpRequestHandler for example.
Additional Reading:
Spring MVC and Servlets 3.0 - Do you still need web.xml?
What happens behind the scenes of deploying a Spring MVC application to tomcat outside of eclipse?
What's the difference between #Component, #Repository & #Service annotations in Spring?
Spring MVC: difference between <context:component-scan> and <annotation-driven /> tags?
Difference between <context:annotation-config> vs <context:component-scan>
ContextLoadListener and DispatcherServlet
Related
It seems to be, that Spring Tool Suite 3.8.3 ignores the newer MVC mapping annotations #GetMapping, #PostMapping etc. on creating the request mapping view. If a #RestController annotated class uses #RequestMapping only, all handler methods are shown in both Spring Tools => Show RequestMappings and Spring Explorer => Beans => Request Mapping. But if only the #RestController annotated class uses #RequestMapping and all handler methods uses #GetMapping, #PostMapping or #DeleteMapping, then those handler method mapping are not shown.
Boot Dashboard can show these request mapping if app is running. However, there is no support probably to show these in Request Mappings view based on annotations scanning. Feel free to raise this issue via Spring-IDE GitHub page: https://github.com/spring-projects/spring-ide/issues
I am using #controller in my controller class which internally creates bean. For this controller I need to use #postConstruct and #preDestroy methods, #postConstruct is working fine but #preDestroy is not working. It means Bean is not destroying. So how can I destroy bean in spring MVC(annotation based)(I am not using ApplicationContext).
Correct me if my assumption was wrong.
WHen you say you dont use application context, do you mean to say that you are not using xml based configuration and are using java annotation config?
With spring mvc controllers, #PreDestroy annotated method will be called on session expiry (unless it's prototype scoped)
Here is a post #PreDestroy on Session-scoped Spring MVC Controllers
Here is a good explantation on spring bean life cycle http://www.journaldev.com/2637/spring-bean-life-cycle-methods-initializingbean-disposablebean-postconstruct-predestroy-aware-interfaces
I found out that if I set the bean scope to singleton, I can get PreDestroy called but not if I set it to prototype.
I have a query regarding how Controllers actually serve the requests..when compared to servlets.
Servlets when instantiated ..have only 1 instance and for each request spawns a thread. How
does Spring MVC controllers serve requests.
Regards
I'd like to expose the backend as 'Resources' (like Restlet) and eliminate the Service Layer so a Rest Resource can direclty interact with a Dao. This way the Resource is the contract and not the Interface.
Is there a problem using #Transactional semantics on a Spring MVC 3 Controller if the transactions are managed locally by Spring? Any gotchas with Rollback and catching exceptions?
#RequestMapping(value = "/user/{userId}", method = RequestMethod.PUT)
#ResponseStatus(HttpStatus.OK)
#Transactional
public void updateUser(#PathVariable Long userId, #RequestBody ProfileUser user) {
// dao update
}
spring config:
<tx:annotation-driven />
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
I think you could run into issues here. By default Spring will use a JDK dynamic proxy to apply the transactional behaviour to your method. This relies on your controller implementing a suitable interface i.e. one which exposes an updateUser method. There is an excellent blog post on the Spring blog.
It is likely that you'll see an error due to Spring failing to find the method on the proxy.
You can use your above approach if you tell Spring to use CGLIB based proxies. This is described in the documentation here.
It seems natural that a HttpServlet running in OSGi environment (i.e. registered in OSGi HttpService) would want to call some OSGi services to accomplish it's tasks. The question is how to obtain references to these OSGi service inside the servlet.
One way would be to inject dependencies into the HttpServlet instance that is being registered to the OSGi HttpService like this:
MyServlet servlet = new MyServlet();
servlet.setFooService(fooService);
httpService.registerServlet("/myservlet", servlet, initparams, context);
I'm not sure if this is a valid approach since in non-OSGi environment the servlet life-cycle is managed by the Web Container and hence the service reference would not be injected for the servlet instances created later on.
There is another way to solve this when using PAX Web as an implementation of the OSGi HttpService. PAX Web exports the OSGi BundleContext into the ServletContext as a special attribute "osgi-bundlecontext". The BundleContext can then be used to obtain necessary service references:
public void init(ServletConfig servletConfig) throws ServletException {
ServletContext context = servletConfig.getServletContext()
BundleContext bundleContext =
(BundleContext) context.getAttribute("osgi-bundlecontext");
ServiceReference serviceRef =
bundleContext.getServiceReference("com.foo.FooService")
}
However this approach is rather ugly and ties you to a concrete implementation of the OSGi HttpService. Do you know any other (and possibly better) solution to this problem?
If you use a setter for the dependency on the service, as you have shown, it can work outside of OSGi as well. You just need to use some other dependency injection mechanism. If there is none, you could provide a subclass that initializes the servlet using JNDI lookups or from the servlet context.
public class MyServlet_AdapterForMissingDI extends MyServlet{
public void init(ServletConfig config){
setFooService(getItFromSomewhere());
}
}
The point being that if you have DI capabilities that can inject setFooService, you can just use the same servlet in OSGi and elsewhere, if you do not (and still want to support this case), you provide an adapter.
On a related note, check out Felix SCR to configure your object's dependencies, and Pax Web Extender Whiteboard, which takes care of hooking your servlet up with the HttpService.
Specifically, without SCR and Whiteboard, you need to think about the case when the fooService becomes unavailable later, or the HttpService gets started after your servlet.
In these cases your servlet would have a reference to a dead service that prevents the bundle from being garbage-collected, or your servlet would not be registered with the HttpService.
Update: Here is the SCR descriptor I use for one of my servlets. SCR handles servlet instantiation, life-cycle, registration (via Whiteboard), and dependencies. There is no OSGi-specific code in the servlet. There is not even the need for a BundleActivator anymore (SCR registers all services):
<component name="oracle.statusServlet" >
<implementation class="mypackage.DataSourceStatusServlet"/>
<property name="service.description" value="Oracle DataSource status servlet" />
<property name="alias" value="/OracleDataSourceStatus" />
<property name="servlet-name" value="Oracle DataSource status servlet" />
<service>
<provide interface="javax.servlet.Servlet" />
</service>
<reference name="DATASOURCES"
interface="javax.sql.DataSource"
cardinality="0..n" policy="dynamic"
bind="bindDataSource" unbind="unbindDataSource"/>
</component>
The dependencies for the servlet are specified in the reference tag. SCR will do the service lookup and binding.
May be an old post and you already might have got the answer..
Are you launching felix or whatever OSGi container yourself. If that is the case you can set the bundle context as an attribute to the servlet context.
Whats wrong in using an http service by PAX. ultimately the thread management and other aspects are taken care of by the servlet container in which you run this http service.
You could inject the services into some object, which is then queried by the servlets.