Spring AOP logging for HTTP request - spring

I am trying to log the http request in controller by aop. However, in the aspect code, if I
httpServletRequest.getInputStream()
then the request data will not be able to retrieve in main flow.
So, I created another public method with in the controller which pass in the request string
public String processRequest(String data){...}
and this method is a pointcut for logging the "data".
But the problem is, seems the point cut for this method is not be able to identify by Spring, there is no logging for this method. I need help on this.
Here is the define for the aop
<bean id="myLogger" class="com.my.MyLogger" />
<aop:config>
<aop:aspect id="Log" ref="myLogger">
<aop:around method="log" pointcut="execution(public * com.my.controller.processRequest(..))" />
</aop:aspect>
</aop:config>

Spring AOP by default uses AOP proxies. So your original bean is wrapped with generated proxy bean and all "outside" calls go through the proxy. Internal method calls (within the same bean) bypass proxy.
It's nicely explained here: http://static.springsource.org/spring/docs/2.5.5/reference/aop.html#aop-understanding-aop-proxies

Related

Clarification needed on Spring MVC without using Annotation

I am trying to understand Spring MVC in more detail what I currently know. I am referring to online tutorials and books. As I understand, Spring MVC framework has "Front controller" and "MVC" design patterns.
The front controller (DispatcherServlet) uses the HandlerMapping for mapping URL to the controller classes. I am not using annotations because I want to understand what the framework does behind the scenes.
In this quest, I created a simple web-application based on Spring MVC, the code is below:
Controller code:
public class SimpleSpringController extends AbstractController {
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest req, HttpServletResponse res) throws Exception {
ModelAndView mw = new ModelAndView("welcome","welcomeMessage", "welcome user!");
return mw;
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<display-name>FirstSpringMVCProject</display-name>
<servlet>
<servlet-name>spring-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>spring-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Spring xml configuration
<beans>
<bean id="HandlerMapping1" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean name="/welcome" class="com.example.controller.SimpleSpringController"/>
<bean id="viewResolver1" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix"> <value>/WEB-INF/</value> </property>
<property name="suffix"> <value>.jsp</value> </property>
</bean>
</beans>
The application works as expected.
The concepts which I am not able to understand is on the spring configuration xml where we specify the HandlerMapping and ViewResolver implementations.
For example, we have the following bean definition in the above spring xml configuration:
<bean id="HandlerMapping1" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
In above xml config, org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping is one of the implementations of the HandlerMapping interface.
The bean id for this is HandlerMapping1, which is just a random identifier ( I could have very well chosen MyHandlerMapping). The following are the doubts:
Who reads this configuration file? Do front controller read this configuration file?
How does the framework knows that the id of HandlerMapping implementation in above case is HandlerMapping1. Usually we do getBean("beanId"), where we specifically know what a particular bean id is. How come spring framework is automatically infer that this is the implementation class of HandlerMapping.
Any inputs to understand this would be of great help.
Initialization
In Spring the front controller is the DispatcherServlet, this extends the FrameworkServlet. The FrameworkServlet by default creates a XmlWebApplicationContext and tries to read an XML file named <servlet-name>-servlet.xml (this is when using a web.xml!). (All this can be overridden by setting the appropriate init-params for the configured DispatcherServlet).
The DispatcherServlet will after loading eventually call the initStrategies method. This method will configure the delegation strategies for the DispatcherServlet. It will first try and detect most of the strategies by type (like HandlerMaping, HandlerAdapter, ViewResolver etc) and some by name (localeResolver, themeResolver, messageSource etc.). If that cannot be found the default strategies for a given interface will be installed. Those defaults are defined in the DispatcherServlet.properties inside Spring.
Important: As soon as you define a strategy yourself the defaults for that strategy don't apply anymore!. For instance if you have a BeanNameUrlHandlerMapping in your configuration, the default configuration for HandlerMapping isn't loaded anymore as you provided explicit configuration.
Request Handling
After startup the DispatcherServlet is ready to handle request.
Image comes from the Spring Framework reference guide
Handler Selection and execution
What happens is when a request is handled by the DispatcherServlet it will check all configured HandlerMappings to see if one is able to provide a handler (a Controller or #Controller is just one of the handler types that can be handled) for the given request. As soon as a handler is found, it will lookup a HandlerAdapter for the detect handler. If that is also found the found handler together with the current HttpServletRequest and HttpServletResponse are passed to the HandlerAdapters handle method.
View resolution
Now if a ModelAndView is being returned from the HandlerAdapter.handle method a View is going to be resolved if the ModelAndView.getViewName() method returns a name, this is going to be passed on the an to a ViewResolver to be resolved into a View.
When a View is either being resolver or being returned from the ModeAndView.getView() method, the render method is going to be called to let the chosen View render itself. With the (optional) model from the ModelAndView class.
Exception Handling
When an exception occurs during processing of the request this exception is first being passed to the configured HandlerExceptionResolvers. If one of them can handle it the selected HandlerExceptionResolvers resolveException method is being invoked. This method, just like the HandlerAdapter.handle method can return a ModelAndView, when this happens this is processed in the same way as a normal request (see View Resolution).
Note: This is also to some degree documented in the javadoc of the DispatcherServlet. You can find all the default strategies and well known names in there, as well as a explanation of the request handling flow.
The controller does not read the xml file, Spring does.
Your spring xml configuration is loaded in by Spring which wires everything together. Autowiring is taking place which is wiring by the Type, of which HandlerMapping1 can provide for the interface HandlerMapping.
Interestingly BeanNameUrlHandlerMapping is the default handler mapping class, so it is the one created by the DispatcherServlet when Spring cannot find any handler mapping class declared.
If you want to try and see something break, create a duplicate bean named HandlerMapping2 and read the error logging.
Spring framework reads the xml.
Well, for spring MVC to work, the handler should be instantiated.
The spring MVC framework needs to resolve the mappings and so we
have handlers like BeanNameUrl..., ControllerBeanNameHandlerMapping,
etc
However, HandlerMapping is not generally used by your application
code. So you need not specify whether this bean is autowired by type
or not. It is used by the framework. So it is autowired in the
framework classes by type.
You can try defining the bean in the xml without any id, name
something like
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
and it should still work.
Id or name is required only when you want to refer to the bean by id
or name for your use. Framework classes which need this handler
mapping don't refer to the bean of HandlerMapping type by id or
name. Framework will 'scan' the xml (or the loaded classes) and if
it finds a concrete class in there of type
(org.springframework.web.servlet.HandlerMapping) then it won't
complain.
To think of a similar case for example, when you run the junit
tests, the engine will scan for all the methods annotated with #Test
and it will 'know' that these are the methods it needs to execute as
tests. It does not matter what the names of test methods are.
Hope this answers the query.

How to intercept functions from those imported external packages by AOP

For example, now I want to intercept the method split() of java.lang.String by AOP.
Is it possible?
I have tried some normal methods but it did not work.
#Aspect
public class TestAspect {
#Before ("execution (* java.lang.String.split(..))")
public void logBeforeString(JoinPoint joinPoint) {
System.out.println("SPLIT BEGIN");
}
}
Below is the configuration file :
<!-- Aspect -->
<aop:aspectj-autoproxy />
<beans:bean id="TestAspect" class="com.dong.partner.aspect.TestAspect" />
With other pointcuts in my own project, they work well without problems.
So anyone knows how to intercept the imported external packages?
No, nothing in java.lang can be advised using execution. See this question for a more detailed explanation.
So anyone knows how to intercept the imported external packages?
You're using <aop:aspectj-autoproxy /> which means that Spring is using proxy based AOP. Essentially, Spring is creating a wrapper around each of your beans if the bean is advised with AOP. When a method on one of your beans is called, it hits the proxy/wrapper first. The proxy decides whether it should invoke your bean directly or whether one or more aspects should be called.
There are limits to the type of advice you can use with proxy based AOP. To intercept calls from your code to non-bean classes you need to switch to compile time or load time weaving with aspectj and use call pointcuts instead of execution pointcuts. The aspectj compiler will rejigger your bytecode so that any calls from your code to java.lang.String are rewritten to invoke the call pointcut.
Interestingly, this question had the opposite issue that you're experiencing.

How do I add custom interceptors to my annotation scanned spring-ws endpoint

I am using Spring-ws 2.1.4.RELEASE and Spring 3.2.8.RELEASE.
I am trying to add an interceptor to my endpoint but so far no luck even though I think my setup is very basic.
In my Spring-ws XML I have:
<sws:interceptors>
<bean class="org.springframework.ws.soap.server.endpoint.interceptor.SoapEnvelopeLoggingInterceptor"/>
</sws:interceptors>
<sws:annotation-driven/>
<context:component-scan base-package="package.with.my.endpoints" />
<bean id="messageFactory" class="org.springframework.ws.soap.axiom.AxiomSoapMessageFactory">
<property name="payloadCaching" value="true"/>
</bean>
In my Endpoint annotated bean I use the Spring-ws #Action annotation for ws addressing mapping:
#Endpoint("MedicineCardIdwsEndpoint")
public class MedicineCardIdws {
#Action("http://someuriandversion#GetMedicineCardIdws")
#ResponsePayload
public String getMedicineCard(#RequestPayload Element payload, SoapMessage soapMessage) {
return "";
}
However nothing is logged by the interceptor when I send a request for my endpoint. At first I thought I had configured log4j wrongly. However, if I create a breakpoint in the first line of org.springframework.ws.server.endpoint.AbstractLoggingInterceptor#handleRequest the breakpoint is never triggered.
Then I put a breakpoint inside org.springframework.ws.soap.server.SoapMessageDispatcher#headerUnderstood I can see that the only interceptor that is registered for my Endpoint is the org.springframework.ws.soap.addressing.server.AddressingEndpointInterceptor which got added because of the Action annotation.
I thought that any global interceptors in the XML configuration would end up being added to the interceptor chain for all endpoints? However it seems this is not the case. It is not just the logging interceptor, even custom interceptors are not added. So I must be doing something wrong.
I am fairly new at using Spring-ws - did I miss something in my config, or is there an annotation I need to add in order to add interceptors for annotation scanned endpoints?
Is there another way I can add interceptors to my interceptor chain when using component scanning and annotations for Spring-ws or do I need to configure all of it in XML in order to be certain that my interceptors are added to my endpoints?
I found that if I use #SoapAction annotation instead of the WS-Addressing #Action (bot from Spring-ws packages) my custom interceptors from the XML config will get added to the endpoint.
I also found this thread in the Spring forums suggesting a workaround if #SoapAction is not an option: http://forum.spring.io/forum/spring-projects/web-services/100060-interceptors-not-working-for-ws-addressing-endpoint-action

Spring Web MVC 3.1.1 argument resolver called before interceptor

I'm configuring my Spring MVC 3.1.1 app as summarized below. Logging shows that 'MyArgumentResolver.resolveArgument' is invoked before 'MyInterceptor.preHandle'. When using both in an old fashion configuration (with exclicitly defined AnnotationMethodHandlerAdapter bean etc.) they are invoked vice versa. I read that <mvc:annotation-driven> is somehow critical, since its configuration does not complement other settings of mvc: namespace. Am I facing the same problem?
<mvc:annotation-driven>
<mvc:message-converters>
...
</mvc:message-converters>
<mvc:argument-resolvers>
<bean class="[...].MyArgumentResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/home/**" />
<bean class="[...].MyInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
Many Thanks!
Spring 3.1 with <mvc:annotation-driven> uses a different set of classes for handling requests - e.g., AnnotationMethodHandlerAdapter is replaced with RequestMappingHandlerAdapter. You can read more about that here: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-31-vs-30
In order to work properly with those classes, they've added a new HandlerMethodArgumentResolver that supersedes the old WebArgumentResolver interface. However, I believe that Spring will automatically try to "upgrade" old WebArgumentResolvers by wrapping them in an AbstractWebArgumentResolverHandlerAdapter, which is the behavior that I was seeing during the process of upgrading. The JavaDoc for AbstractWebArgumentResolverHandlerAdapter says:
Note: This class is provided for backwards compatibility. However it is recommended to re-write a WebArgumentResolver as HandlerMethodArgumentResolver. Since supportsParameter(org.springframework.core.MethodParameter) can only be implemented by actually resolving the value and then checking the result is not WebArgumentResolver#UNRESOLVED ...
After stepping through the code, I think what may be happening in your case is that it the new classes call the supportsParameter function before executing preHandle in the interceptors, but the implementation of AbstractWebArgumentResolverHandlerAdapter actually calls the resolveArgument method and checks for 'UNRESOLVED' as the return type in order to determine if the argument resolver supports the given argument, which would give the appearance of them being called out of order.
I suspect if you rewrite your argument resolver to implement the new HandlerMethodArgumentResolver interface, it will solve your problem.

Why doesn't just autowiring a field in a GWT servlet in Spring work?

Simply marking a field as #Autowired in a GWT servlet does not work as intended. The code will compile and the web application will start up - which means Spring was successfully able to autowire the field, but when the servlet is actually hit by client-side code, it will yield a NullPointerException - like there's a different, uninitialized copy of the servlet being hit.
I've found several ways on the web to get this working, one is by using a base servlet class that does some Spring logic but doing this means every GWT servlet must extend this base class. The other way was by using AspectJ and the #Configurable Spring annotation. There was very little configuration involved here and it just magically worked.
My question is why doesn't just autowiring the field just work as intended? What is GWT doing that causes this to break.
The code will compile and the web application will start up - which
means Spring was successfully able to autowire the field
Not necessarily. The web container can instantiate a servlet without any help from Spring. Which you could be experiencing:
but when the servlet is actually hit by client-side code, it will
yield a NullPointerException - like there's a different, uninitialized
copy of the servlet being hit.
try overriding Servlet's init():
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
WebApplicationContextUtils.getWebApplicationContext(config.getServletContext())
.getAutowireCapableBeanFactory().autowireBean(this);
}
When the RPC service is called from the client, the "server-side" looking at the called URL and the servlets mapping will find the class, will make the instance and it will serve the request. Meaning if you have #Autowired annotation, or you already have an instance of the RPC class in the spring context, it does not matter. The new instance will be created and it won't "know" about Spring.
I resolve this by implementing a class which extends RemoteServiceServlet and implements Controller (from Spring MVC) and ServletContextAware.
This way you can map every RPC service by URL using the Spring MVC approach, for ex:
<bean id="publicUrlMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/myFirstRpc">firstRpcServiceBeanRef</prop>
<prop key="/mySecondRpc">secondRpcServiceRef</prop>
</props>
</property>
</bean>
You also avoid the declarations for every single RPC servlet in web.xml, the mappings are clean and you have the Spring injection.
You declare only a single mapping in web.xml for org.springframework.web.servlet.DispatcherServlet which will serve all RPC calls.
There are couple of examples on the web with explanation about GWT RPC and Spring MVC controller integration.
Hope this will help.
It turns out that when using Spring at least, there's a MUCH simpler way to do this such that you can use #Autowired and it doesn't involve massive configuration or base classes. The caveat is that you must also use AspectJ. Here's what you need for your GWT servlet:
#Configurable
public class MyGwtServiceImpl extends RemoteServiceServlet implements MyGwtService
{
#Autowired
private MyService service;
// ...
}
And in your Spring config make sure you also have:
<!-- enable autowiring and configuration of non-spring managed classes, requires AspectJ -->
<context:spring-configured/>
One final note. If you are also using Spring security with your GWT application (and in your GWT servlets), you will need to make sure you define the correct mode to ensure the AspectJ weaving is done correctly (i.e., you get both #Secured annotation processing AND the #Autowired processing) you will need:
<!-- turn on spring security for method annotations with #Secured(...) -->
<!-- the aspectj mode is required because we autowire spring services into GWT servlets and this
is also done via aspectj. a server 500 error will occur if this is changed or removed. -->
<security:global-method-security secured-annotations="enabled" mode="aspectj"/>

Resources