Announcement Announcement Module
Collapse
No announcement yet.
Spring AOP Aspect Not Executing Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Spring AOP Aspect Not Executing

    Hello - I'm hoping someone can spot something wrong with my configuration. I'm trying to execute an aspect on a class that is a Servlet. I've created the following implementation and have made the servlet a Spring Managed bean that is injected into a ServletDelegationController class. I am expecting that when the "doGet" method of the servlet is called, the aspect should execute. Unfortunately, that isn't the case. I took it a step further and created a SimpleBean that is injected into the servlet and added a pointcut expression for the call to the "logSomething" method. This method call DOES execute the aspect.

    Please see the various configuration files and the SimpleAroundAspect class below for the details of my config. (Note: I've also verfied that the package, class and method names are correct)

    Thanks in advance.

    web.xml
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app>
    	<display-name>ABCNet Web</display-name>
    	
    	<context-param>
    		<param-name>contextConfigLocation</param-name>
    		<param-value>/WEB-INF/applicationContext.xml</param-value>
    	</context-param>
    	
    	<listener>
    		<listener-class>
    			org.springframework.web.context.ContextLoaderListener
    		</listener-class>
    	</listener>
    	<listener>
    		<listener-class>
    			org.springframework.web.context.request.RequestContextListener
    		</listener-class>
    	</listener>
    
        <servlet>
            <servlet-name>DispatcherServlet</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
    			<param-name>contextConfigLocation</param-name>
    			<param-value>/WEB-INF/applicationContext.xml</param-value>
    		</init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>DispatcherServlet</servlet-name>
    		<url-pattern>/asset</url-pattern>
        </servlet-mapping>
    
    </web-app>

    applicationContext.xml
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans>
    	<context:property-placeholder/>
    
    	<import resource="intranet-MonitoringSpringAspects.xml" />
    
    	
    	<bean id="log4jInitialization"
    		class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    		<property name="targetClass" value="org.springframework.util.Log4jConfigurer" />
    		<property name="targetMethod" value="initLogging" />
    		<property name="arguments">
    			<list>
    				<value>classpath:log4j.dev.xml</value>
    			</list>
    		</property>
    	</bean>
    	
    
    	<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    		<property name="mappings">
    			<props>
    				<prop key="/asset">assetServletDelegationController</prop>
    			</props>
    		</property>
    	</bean>
    
    	<bean id="assetServletDelegationController" class="com.abc.intranet.web.servlet.ServletDelegationController">
    		<property name="servlet" ref="assetServletBean"/>
    		<property name="servletName">
    			<value>AssetServlet</value>
    		</property>
    		<property name="initParameters">
    			<props>
    				<prop key="folderFilter">/intranet/resources</prop>
    			</props>
    		</property>
    	</bean>
    
    	<bean id="assetServletBean" class="com.abc.intranet.web.servlet.IntraAssetServlet">
    		<property name="simpleBean" ref="aSimpleBean"/>
    	</bean>
    
    	<bean id="aSimpleBean" class="com.abc.intranet.web.servlet.SimpleBean"/>
    	
    
    	<context:annotation-config/> 
    
    </beans>

    intranet-MonitoringSpringAspects.xml
    Code:
    <?xml version="1.0" encoding="UTF-8"?>
    <beans >
    
    	<aop:config proxy-target-class="true" >
    		<aop:pointcut id="intranetMonitoringScope"
    			expression="(execution(public * com.abc.intranet.web.servlet.IntraAssetServlet.doGet(..))) ||
    			(execution(public * com.abc.intranet.web.servlet.SimpleBean.log*(..))) " />
    		<aop:aspect id="myIntranetMonitoringAspect" ref="intranetMonitoringAspect">
    			<aop:around method="monitor" pointcut-ref="intranetMonitoringScope" />
    		</aop:aspect>
    	</aop:config>
     
    	<bean id="intranetMonitoringAspect" class="com.abc.intranet.web.servlet.SimpleAroundAspect" />
    	
    </beans>
    SimpleAroundAspect class
    Code:
    package com.abc.intranet.web.servlet;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.Signature;
    
    public class SimpleAroundAspect {
    
        private org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(SimpleAroundAspect.class);
    
        /**
         *	Default constructor
         */
        public SimpleAroundAspect() {
            super();
        }
    
        
        public Object monitor(ProceedingJoinPoint thisJoinPoint) throws Throwable
        {
            Signature signature = thisJoinPoint.getSignature();
            log.info("Before Call to proceed on joinpoint: " + signature.getDeclaringTypeName() + "." + signature.getName());
    
            Object result;
            try
            {
                result = thisJoinPoint.proceed();
            }
            finally{
                log.info("After Call to proceed on joinpoint: " + signature.getDeclaringTypeName() + "." + signature.getName());
            }
            return result;
        }
    
     }
    IntraAssetServlet class
    Code:
    package com.abc.intranet.web.servlet;
    
    import java.io.IOException;
    
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.apache.log4j.Logger;
    
    public class IntraAssetServlet  extends HttpServlet {
    
        /** Support serialization */
        private static final long serialVersionUID = 1L;
    
        private static final Logger log = Logger.getLogger(IntraAssetServlet.class);
        
        private SimpleBean bean = null;
        
        public void setSimpleBean(SimpleBean theBean){
            bean = theBean;
        }
    
        public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            log.info("Inside the IntraAssetServlet before calling the beans logSomething method.");
            bean.logSomething();
            log.info("Inside the IntraAssetServlet after calling the beans logSomething method.");
            
        }
    
    }
    Last edited by kconway; Nov 6th, 2008, 07:01 PM. Reason: removed company name

  • #2
    You can only intercept externally called methods. So basically you can only intercept the methods exposed on the Servlet interface, doGet isn't one of them. That is basic aop proxy behavior. If want to intercept internal method calls you need something like AspectJ with loadtime weaving.

    Comment


    • #3
      Hi Martin - Thanks for your response. With my new found understanding of the problem, I modified the pointcut expression to be the following

      Code:
      <?xml version="1.0" encoding="UTF-8"?>
      <beans >
      
      	<aop:config proxy-target-class="true" >
      		<aop:pointcut id="intranetMonitoringScope"
      			expression="(execution(public * com.abc.intranet.web.servlet.IntraAssetServlet.service(..))) ||
      			(execution(public * com.abc.intranet.web.servlet.SimpleBean.log*(..))) " />
      		<aop:aspect id="myIntranetMonitoringAspect" ref="intranetMonitoringAspect">
      			<aop:around method="monitor" pointcut-ref="intranetMonitoringScope" />
      		</aop:aspect>
      	</aop:config>
       
      	<bean id="intranetMonitoringAspect" class="com.abc.intranet.web.servlet.SimpleAroundAspect" />
      	
      </beans>
      Basically changing the pointcut to execute on the service method from the Servlet interface. It appears that it still is not executing the advice. Am I missing something else?

      Thanks again.

      Comment


      • #4
        The pointcut looks fine. What does your ServletDelegationController (that seems to delegate to a servlet instantiated as a bean) look like?

        -Ramnivas
        Last edited by ramnivas; Nov 10th, 2008, 03:06 PM.

        Comment


        • #5
          Yes. It is just delegating to the Servlet Class that is instantiated as a bean. My understanding from reading the Spring AOP documentation is that the Spring AOP framework can only execute pointcuts on spring managed beans. That being the case I created the Servlet as a spring managed bean and inject it into the ServletDelegationController. The ServletDelegationController is configuring the servlet with whatever initParameters are set in the configuration and then the controller executes the servlets service method as shown below

          Code:
          	protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
          	    throws Exception {
          
          		this.servlet.service(request, response);
          		return null;
          	}
          Last edited by kconway; Nov 10th, 2008, 09:39 AM.

          Comment


          • #6
            Try changing
            Code:
            this.servlet.service(request, response);
            to
            Code:
            this.servlet.doGet(request, response);
            Since there is no service() method implemented in IntraAssetServlet, the pointcut doesn't match. However, assuming that you haven't changed the ServletDelegationController since your first post, your original pointcut (that used doGet(..)) should have worked as well. So there may be a different problem lurking here.

            If this doesn't work, change your pointcut to use IntraAssetServlet.*(..) just to get a handle on what may be going on.

            Also, check the type of the servlet field in ServletDelegationController. It should be of a proxy type.

            -Ramnivas

            Comment


            • #7
              Hi Ramnivus - according to an earlier reply by Marten Deinum, "You can only intercept externally called methods. So basically you can only intercept the methods exposed on the Servlet interface, doGet isn't one of them. That is basic aop proxy behavior. If want to intercept internal method calls you need something like AspectJ with loadtime weaving.". So with that in mind, I changed the original pointcut expression from "doGet" to "service" which is implemented by the GenericServlet class which ultimately the IntraAssetServlet extends. I've also tried the "IntraAssetServlet.*(..)" that you mentioned and that doesn't work either. However, when you say "Also, check the type of the servlet field in ServletDelegationController. It should be of a proxy type.", can you tell me, what proxy type you think it should be? Thanks for your input.

              Comment


              • #8
                Hmmm... IntraAssetServlet.*(..) didn't work is interesting. Can you write an integration test, where you load the application context, get the ServletDelegationController bean, and call handleRequestInternal() passing it a mock HttpServletRequest and HttpServletResponse? I thing this may help triage the problem.

                As for the proxy, the class name should contain "CGLIB" and "Proxy" strings.

                Also, which Spring version are you using?

                -Ramnivas

                Comment


                • #9
                  Spring 2.5.5. I'll get back with the results of testing with mocks.

                  Comment

                  Working...
                  X