I am unable to configure HttpServletRequest in application context in my spring environment.
below is the code I tried:
<bean id="request" class="javax.servlet.http.HttpServletRequest">
</bean>
<bean id="rwEloquaControllerService" class="com.rightwave.eloqua.RWEloquaControllerService">
<property name="request" ref="request" />
</bean>
RWEloquaControllerService class code for getter setter:
HttpServletRequest request;
public HttpServletRequest getRequest() {
return request;
}
public void setRequest(HttpServletRequest request) {
this.request = request;
}
But when I start my server, exceptions occurred due to application context error. can any one tell me how to configure HttpServletRequest object in application context.
Let's talk about some basic concepts first.
In my Knowledge, it's not possible to instantiate an interface in application context. How do you new an interface without give it real implementation? It's impossible.
You write bean in application context so that Spring can instantiate them. However, the request you want is generated by servlet container. It's not created by Spring.
If you want to inject request in your controller, just add the following code in your controller. Spring doesn't create the request, Spring just get it from servlet container then inject it into the controller.
private #Autowired HttpServletRequest request;
Based on your comment:
Can I not instantiate an interface in application context. Basically, I need request object to get context, then springContext and then get a bean. So at first point I need request
Simply make you controller implement org.springframework.context.ApplicationContextAware. You will have to add the public void setApplicationContext(ApplicationContext applicationContext) throws BeansException method, which you can use to set the provided applicationContext to a member variable.
You can then use it to query the context for spring-managed beans.
Note: the setApplicationContext method will be invoked by Spring after your controller has been created but before afterPropertiesSet is invoked (if you implement InitializingBean).
Related
Can anyone advise how I might retrieve the settings bean from within the method:
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException
Inside a custom Authentication Provider in Spring?
I am currently learning Spring security as I work on some assigned software.
I am making some adjustments to a Spring custom Authentication Provider that inherits from LdapAuthenticationProvider.
As part of the code, I want to retrieve some settings from a custom bean that is described in my applicationContext.xml thus:
<bean name="mySettings" class="au.org.myOrganisation.MySettingsBean"></bean>
This allows me to retrieve settings that are specified in the properties file which is identified by the context:property-placeholder tag in applicationContext.xml thus:
<context:property-placeholder location="classpath:mySettings.properties" />
Ordinarily, I pull this bean in when I need the data it contains like so:
WebApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
MySettingsBean mySettings = (MySettingsBean) ctx.getBean("mySettings");
However, when I put this code to retrieve the bean in the method:
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException
in my Spring custom Authentication Provider that inherits from LdapAuthenticationProvider in order to overrides the method of the same name, I get an exception thus:
org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [default] in context with path [/ice] threw exception
java.lang.IllegalArgumentException: FacesContext must not be null
at org.springframework.util.Assert.notNull(Assert.java:134)
at org.springframework.web.jsf.FacesContextUtils.getWebApplicationContext(FacesContextUtils.java:50)
Indicating that the line
WebApplicationContext ctx = FacesContextUtils.getWebApplicationContext(FacesContext.getCurrentInstance());
Is failing due to a lack of a FacesContext.
Thanks heaps
David :-)
I figured it out.
There are two different (but similar) methods for retrieving the beans in Spring.
One way is to add the ApplicationContext to the class where you need it using an #Autowired annotation thus:
import org.springframework.context.ApplicationContext;
...
class MyClassThatNeedsAppContext {
#Autowired
private ApplicationContext appContext;
...
}
Then, at the point where you need the bean, you can get it using this code:
MySettingsBean mySettings = this.appContext.getBean(MySettingsBean.class);
The other method is similar (and dispenses with the whole FacesContextUtils static method call).
You add an Autowired reference to the WebApplicationContext thus:
import org.springframework.web.context.WebApplicationContext;
...
...
class MyClassThatNeedsAppContext {
#Autowired
private WebApplicationContext webContext;
...
}
And then when you need the bean, you can retrieve it thus:
MySettingsBean mySettings = (MySettingsBean) this.webContext.getBean("mySettings");
This method works just fine in the middle of a custom AuthenticationProvider. I suspect (but have not yet tested) that it would work anywhere in the application.
The TeamCity plugin API allows adding controllers by extending their BaseController, which is a thin wrapper around Spring's AbstractController.
When I extend BaseController I can inject beans into the constructor in usual Spring manner. This is managed by a beans definition file like standard spring.,
To provide a Controller I must extend BaseController, override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response), and add the controller to the beans definition. I register a URL route as part of constructor initialisation.
That's about all the extension points available to me for Controller.
I was hoping to be able to write small framework that would allow me to annotate my classes with #RestController and #RequestMapping, etc.
What I think I need to do is:
Wire up an annotation processor to find my controllers and their methods.
Build some sort of mapper which maps #RequestMapping annotated methods to routes
Wire up some content handlers, eg serialising/unserialising for JSON and XML
Dispatch incoming requests to the appropriate method inside my handleRequest method
Most of the above has already been written in Spring and Jersey, and I am wondering where I start researching that.
What classes provide the above functionality?
I've tried a few things to try and instantiate MVC, but it seems to break when ApplicationContext is not available.
Not a TeamCity user. However I'll give my two cents, hoping for the best.
Being that you can register Spring Bean(s), why not trying out ClassPathBeanDefinitionScanner?
If you have access somehow to a Spring lifecycle hook, an initialization one, or if you are able to register a Configuration class, you can create a Bean of type BeanFactoryPostProcessor. I'll give you a Java example, but you should be able to translate it to XML pretty quickly.
#Bean
public BeanFactoryPostProcessor beanFactoryPostProcessor(final ApplicationContext applicationContext) {
return new BeanFactoryPostProcessor() {
#Override
public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (beanFactory instanceof BeanDefinitionRegistry) {
try {
final BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
final ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
scanner.setResourceLoader(applicationContext);
scanner.scan("your.base.package");
} catch (final Exception e) {
// Handle
}
}
}
};
}
The ClassPathBeanDefinitionScanner will register all classes with Spring stereotype annotations.
You can also make a class implement the BeanFactoryPostProcessor interface directly.
generally we use Spring context in servlet as follows
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(servlet.getServletContext());
SomeBean someBean = (SomeBean) ctx.getBean("someBean");
But in REST service declared using annotation is not actually servlet. So we do not get getServletContext()
How handle this ?
answer
1) By passing context as parameter to method
#GET
#Path("/create")
#Produces(MediaType.TEXT_PLAIN)
public String createCustomer(#Context ServletContext servletContext){
2) Other solution is using ApplicationContextAware
which is explained here
To get the application context you can have your service implement ApplicationContextAware. Then when the service is created, Spring will call the setApplicationContext method to provide you with the application context. Inside that method you can then store the provided context for later use.
I'm trying to inject a Spring-managed bean and a string value into a servlet. The servlet is defined in context.xml as following:
<bean name="gwtlogging" class="com.somepackage.MyRemoteLogger">
<property name="symbolMapsDirectory" value="/WEB-INF/deploy/gwt/symbolMaps/"/>
<property name="serializationPolicyResolver" ref="serializationPolicyResolver"/>
</bean>
I came across using this method:
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this,
config.getServletContext());
}
This works, but has some disadvantages:
I want to inject beans as defined in context.xml and not per autowiring
I need to inject a string value (not a bean), which seems impossible this way
Ideally I want that all values defined in xml will be somehow injected into servlet instance.
If it's available to you, you can declare a Servlet bean in your XML configuration file, use Spring's WebApplicationInitializer (or write your own ServletContainerInitializer) to load the XML file in a WebApplicationContext, retrieve the Servlet bean, and add it to the ServletContext with add(String, Servlet).
The Servlet instance will have been completely prepared through Spring and will be used by your Servlet container.
I know that I need to register classes annotated with #Controller in my servlet context to make my webapp accesible. Usually, I will do it the following way:
#Configuration
#EnableWebMvc
#ComponentScan({"foo.bar.controller"})
public class WebConfig extends WebMvcConfigurerAdapter {
//other stuff like ViewResolvers, MessageResolvers, MessageConverters, etc.
}
All other configuration classes I added to my root application context. Here is how my dispatcher initializer usually look like:
public class DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { RootConfig.class, ServiceConfig.class };
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
But things are getting more interesting when I started to use WebSockets. To get websockets working, you have to put WebSoketConfig.class to servlet context. Here is my example of WebSocketConfig:
#Configuration
#EnableScheduling
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/chat").withSockJS();
}
#Override
public void configureClientInboundChannel(ChannelRegistration channelRegistration) {
channelRegistration.taskExecutor().corePoolSize(4).maxPoolSize(8);
}
#Override
public void configureClientOutboundChannel(ChannelRegistration channelRegistration) {
channelRegistration.taskExecutor().corePoolSize(4).maxPoolSize(8);
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableSimpleBroker("/queue", "/topic");
registry.setApplicationDestinationPrefixes("/app");
}
}
Also, I've created a service to send a message to the topic:
#Service
public class TimeServiceWsImpl implements TimeServiceWs {
#Autowired
private SimpMessagingTemplate messagingTemplate;
#Override
public void sentCurrentTime() {
long currentTime = System.currentTimeMillis();
String destination = "/topic/chatty";
logger.info("sending current time to websocket /topic/time : " + currentTime);
this.messagingTemplate.convertAndSend(destination, currentTime);
}
}
I need to use this service in some other services (Autowire it). And now I'm in a deadlock:
If I'm trying to create TimeServiceWs bean inside root application context, as expected it doesn't see SimpMessagingTemplate bean and throws NoSuchBeanDefinitionException
If I'm trying to create TimeServiceWs bean inside servlet context, then I'm unable to autowire it to any another service, because root context can't see servlet context beans(as far as I know)
If I move all my configurations to servlet context, all beans are successfully created, but I get the following exception: java.lang.IllegalStateException: No WebApplicationContext found and can't access my webapp
What am I supposed to do? What should be inside root context? What should be inside servlet context? And could you please clarify the difference between these context one more time please?
If you will need any additional information, just let me know.
Most Spring MVC applications have one root context containing all service layer / DAO layer beans, and one servlet context per spring dispatcher servlet of the application, which contains (at least) the controllers of each servlet.
The idea being that is that one application might have several servlet dispatchers, for example one for URL /shopping/* and the other for URL /reporting/*, each with it's own set of controllers.
The controllers of one servlet dispatcher are isolated from each other, meaning although they are also Spring beans, they cannot be injected in each other.
Service layer and DAO beans in the root context are visible in all servlet contexts, so Service layer beans can be injected in any controller, but not the other way around.
The root context is said to be the parent of the controller servlet context/contexts.
It's all meant to be a mechanism of isolating groups of beans from each other to ensure no unmeant dependencies are possible.
Given this and going through the questions:
If I'm trying to create TimeServiceWs bean inside root application context, as expected it doesn't see SimpMessagingTemplate bean and throws NoSuchBeanDefinitionException: Move the SimpleMessagingTemplate to the root context, it's a bean like a DAO that can be useful anywhere in the application so it should be in the shared root context.
If I'm trying to create TimeServiceWs bean inside servlet context, then I'm unable to autowire it to any another service: If it's meant to be autowired to other services, leave it in the root context then.
- If I move all my configurations to servlet context, all beans are successfully created, but I get java.lang.IllegalStateException: No WebApplicationContext found: Do the opposite, move basically all beans to the root context, and leave on the servlet context only the beans that are specific of that part of the application, many times only the controllers.
WebSocket-related config belongs to the DispatcherServlet configuration one way or another. After all the HTTP handshake is processed by the DispatcherServlet through its handler mappings.
You should be able to go with a single Spring context in a deployment scenario where there is only one DispatcherServlet in the web application. Consolidating the configuration into the root context makes more sense if using Spring Security for example although there was a bug with the AbstractAnnotationConfigDispatcherServletInitializer (see SPR-11357). Consolidating into the DispatcherServlet context should also be possible but you wrote that you got exceptions. Can you provide the exception details?
It is also an option to have both root and DispatcherServlet contexts. In that case the WebSocket configuration will be in the DispatcherServlet context and it's not possible to inject the SimpMessagingTemplate into beans in the root context. That actually makes sense since there is one SimpMessagingTemplate to go with each DispatcherServlet (or some other servlet). What's needed is a web layer component, perhaps a thin wrapper around service layer beans (like TimeServiceWs the above example) that can also be injected with the SimpMessagingTemplate. This web layer component essentially serves as a bridge.