0

我有一个 Spring 3.2.4 MVC 应用程序,我想使用 Spring AOP。因此,我创建了一个带有<aop:aspectj-autoproxy />.

我还写了一个 Aspect (采用在网络上找到的代码):

@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);
    }
}

(我实现构造函数只是为了查看 bean 是否在 TOMCAT 启动期间被实例化……确实如此!

但是,每当我输入 LoginLogoutController 的登录方法时,我的 Aspect 的 xyz 方法都不会执行。我的Pointcut的表达是不是错了?

我如何告诉 Spring 执行我的建议?

我的控制器:

@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);
    }
}
}

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>

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" /> -->


我已将大型 appConfig-context.xml 拆分为较小的部分:

  1. 根配置.xml
  2. tx-context.xml
  3. aop-context.xml
  4. appConfig-context.xml(DispatcherServlet 的 MVC 上下文)

虽然在 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.

4

1 回答 1

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.

于 2013-10-15T18:18:15.547 回答