0

I have a Spring 3.2.4 MVC application and I want to use Spring AOP. Hence, I have created a config file with an <aop:aspectj-autoproxy />.

I also have written an Aspect (adopted to code found in the web):

@Component
@Aspect
public class PerformanceMonitoring {
    private static final Logger logger = Logger.getLogger(PerformanceMonitoring.class);

    public PerformanceMonitoring() {
        System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++");
    }

//    @Around("execution(* com.silabs.moka.*(..))")
//    @Pointcut(value="execution(public * *(..))")
//    @Before("execution(* * com.foo.bar.controller.*.*(..))")
    @Before("execution(public DefaultClientResponse<UserProfile> com.foo.bar.controller.LoginLogoutController.login(..))")
    public void xyz(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        String methodName = signature.getName();
        String stuff = signature.toString();
        String arguments = Arrays.toString(joinPoint.getArgs());
        System.out.println("################################################");
        logger.info("Write something in the log... We are just about to call method: "
            + methodName + " with arguments " + arguments + "\nand the full toString: "
            + stuff);
    }
}

(I implemented the constructor just to see if the bean gets instantiated during the start of TOMCAT… and it is!)

However, whenever I enter the login method of the LoginLogoutController the xyz method of my Aspect is not executed. Is the expression of my Pointcut wrong?

How can I tell Spring to execute my Advice?

My Controller:

@Controller
@PropertySource("classpath:xxx.properties")
public class LoginLogoutController {

private static final Logger logger = Logger.getLogger(LoginLogoutController.class);
@Inject
protected Environment env;

/**
 * Returns a json list of first names.
 *
 * @param term the beginning part of the first name
 * @return json string array of first names
 */
@RequestMapping(value = "/login", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public DefaultClientResponse<UserProfile> login(final @RequestParam String userName, final @RequestParam String passWord, final @RequestParam(required = false) String deviceToken, HttpServletRequest req) {

    logger.info("login: " + userName + ", passWord: " + passWord + ", deviceToken: " + deviceToken);
//        logger.info("Communicating with host: " + env.getProperty("url.base"));

    UserProfile up = null;
    up = userProfileService.findUserProfileByNameAndPassword(userName, passWord);

    if (up != null) {
        logger.info("UserProfile for " + up.getFirstName() + " " + up.getLastName() + " found.");
        HttpSession session = req.getSession(true);
        logger.info("Created session with ID:[" + session.getId() + "]");

        // Set session parameters
        session.setMaxInactiveInterval(Integer.valueOf(env.getProperty("xxx.session.timeout")) * 60 * 60);
        session.setAttribute("isAuthenticated", true);
        session.setAttribute("deviceToken", deviceToken);
        session.setAttribute("authInfo", up.getAuthInfo());
        session.setAttribute("KundenID", up.getUserProfileId());
...

        return new DefaultClientResponse<UserProfile>(session.getId(), 0, "", up);
    } else {
        return new DefaultClientResponse<UserProfile>(null, 1, String.format("No user for gogin <%1$s> and password <%2$s> registered.", userName, passWord), null);
    }
}
}

The aop_config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xsi:schemaLocation="http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

<aop:aspectj-autoproxy />
</beans:beans>

The appConfig-context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"  
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:task="http://www.springframework.org/schema/task"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc.xsd
                        http://www.springframework.org/schema/beans 
                        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                        http://www.springframework.org/schema/context 
                        http://www.springframework.org/schema/context/spring-context-3.2.xsd
                        http://www.springframework.org/schema/data/jpa 
                        http://www.springframework.org/schema/data/jpa/spring-jpa.xsd 
                        http://www.springframework.org/schema/tx
                        http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
                        http://www.springframework.org/schema/task
                        http://www.springframework.org/schema/task/spring-task-3.2.xsd
                        http://www.springframework.org/schema/util
                        http://www.springframework.org/schema/util/spring-util-3.2.xsd">


<mvc:annotation-driven />
<task:annotation-driven/>
<context:component-scan base-package="com.foo.bar">
    <context:include-filter type="aspectj" expression="com.foo.bar.aop.PerformanceMonitoring" />
</context:component-scan>


<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<mvc:resources mapping="/resources/**" location="/resources/" />

<!--Placeholder configuration--> 
<beans:bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
    <beans:property name="locations">
        <beans:list>
            <beans:value>classpath:xxx.properties</beans:value>
        </beans:list>
    </beans:property>
    <beans:property name="ignoreUnresolvablePlaceholders" value="true"/>
</beans:bean>


<beans:bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <beans:property name="basename" value="classpath:xxx_messages" />
    <beans:property name="defaultEncoding" value="UTF-8"/>
</beans:bean>

<beans:bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
    <beans:property name="paramName" value="lang" />
</beans:bean>

<!-- Declare the Resolver -->
<beans:bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
    <beans:property name="defaultLocale" value="de"/>
</beans:bean>

<beans:bean id="handlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
    <beans:property name="interceptors">
        <beans:ref bean="localeChangeInterceptor" />
    </beans:property>
</beans:bean>



<beans:bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
    <beans:property name="contentNegotiationManager">
        <beans:bean class="org.springframework.web.accept.ContentNegotiationManager">
            <beans:constructor-arg>
                <beans:bean class="org.springframework.web.accept.PathExtensionContentNegotiationStrategy">
                    <beans:constructor-arg>
                        <beans:map>
                            <beans:entry key="json">
                                <util:constant static-field="org.springframework.http.MediaType.APPLICATION_JSON_VALUE" />
                            </beans:entry>
                            <beans:entry key="xml">
                                <util:constant static-field="org.springframework.http.MediaType.APPLICATION_XML_VALUE" />
                            </beans:entry>
                        </beans:map>
                    </beans:constructor-arg>
                </beans:bean>
            </beans:constructor-arg>
        </beans:bean>
    </beans:property>
</beans:bean>




<!-- Resolves views selected for rendering by @Controllers to .jsp resources 
in the /WEB-INF/views directory -->
    <beans:bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>

<!--Persistence data source--> 
<beans:bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" 
            p:driverClassName="com.mysql.jdbc.Driver" 
            p:url="jdbc:mysql://localhost:3306/m12"
            p:username="root" 
            p:password="">
</beans:bean>

<!--Persistence JPA-->
<jpa:repositories base-package="com.foo.bar.repository"/>

<beans:bean class="org.springframework.orm.jpa.JpaTransactionManager"
            id="transactionManager">
    <beans:property name="entityManagerFactory"
                    ref="entityManagerFactory" />
    <beans:property name="jpaDialect">
        <beans:bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
    </beans:property>
</beans:bean>
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" />

<beans:bean id="entityManagerFactory"
            autowire="default"
            class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <beans:property name="dataSource" ref="dataSource" />
    <beans:property name="packagesToScan" value="com.foo.bar.repository, com.silabs.moka.domain" />
    <beans:property name="jpaVendorAdapter">
        <beans:bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
            <beans:property name="generateDdl" value="false" />
            <beans:property name="showSql" value="false" />
            <beans:property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
            <beans:property name="database" value="MYSQL"/>
        </beans:bean>
    </beans:property>
    <!-- put any ORM specific stuff here -->
    <beans:property name="jpaProperties">
        <beans:props>
            <beans:prop key="hibernate.hbm2ddl.auto">update</beans:prop>  
        </beans:props>
    </beans:property>
</beans:bean>

<!--    <beans:bean id="persistenceExceptionTranslationPostProcessor"
class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" /> -->


I have split up the large appConfig-context.xml into smaller pieces:

  1. root-config.xml
  2. tx-context.xml
  3. aop-context.xml
  4. appConfig-context.xml (MVC context for DispatcherServlet)

Although having this in web.xml:

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/spring/aop-context.xml 
                     /WEB-INF/spring/root-context.xml 
                     /WEB-INF/spring/tx-context.xml
        </param-value>
    </context-param>

at least the aop-context.xml seems not to be considered. When I import aop-context.xml in appConfig-context.xml using <beans:import resource="../aop-context.xml"/> I always get a

HTTP Status 404 - /bar/WEB-INF/views/.jsp

type Status report

message /bar/WEB-INF/views/.jsp

from TOMCAT in the browser. description The requested resource is not available.

du-it
  • 2,561
  • 8
  • 42
  • 80

1 Answers1

1

I never succeeded in having both Spring MVC (for my @Controller classes) and all the other nice AOP stuff (such as @Transactional) in one class. This might be just the cause here as well, but that’s a guess given we do not see all the setup.


Extended answer (now that config is given):

You have these three for the same context:

<aop:aspectj-autoproxy />
<mvc:annotation-driven />
<tx:annotation-driven mode="aspectj" transaction-manager="transactionManager" />

You should have separate contexts for controllers and everything else. Please have a look at @Service are constructed twice for reference to do it correctly. AOP (and thus transactions) will not work in the context for controllers.

Community
  • 1
  • 1
Michael Piefel
  • 18,660
  • 9
  • 81
  • 112
  • I did a suggested but this causes that now neither my services nor my repositories can be found. I put the component-scan for everything but the controllers into root-context.xml and scanning for controllers int the appConfig-context.xml (which is the servlet-context.xml). In web.xml I registered root-config.xml as well as aop_context.xml as contectConfigLocation. – du-it Oct 16 '13 at 10:54
  • I solved the problem by splitting the existing complex contect configuration in smaller pieces. Extracting one part impacted other parts and thus, some exception occured. Services and controllers are found now. It is important to have the tag besides the component-scan tags as you suggested. Without this tag, neither services nor controllers, ... can be found. – du-it Oct 16 '13 at 13:46
  • I was pleased too soon. :( Using a Pointcut like @Before("execution(* *.*(..))") I can see that the Apsect is used during TOMCAT start but when modifing the Pointcut to something like @Before("execution(* com.foo.bar.*(..))") or @Before("within(@org.springframework.stereotype.Controller *)") th Aspect is never used. – du-it Oct 17 '13 at 09:09