簡體   English   中英

Spring 注釋控制器上的 AOP 建議

[英]Spring AOP Advice on Annotated Controllers

我正在嘗試使用 AOP 在帶注釋的 controller 之后進行一些處理。一切都在正常運行,沒有錯誤,但建議沒有被執行。

這是 controller 代碼:

@Controller
public class HomeController {       
    @RequestMapping("/home.fo")
    public String home(ModelMap model) {
        model = new ModelMap();
        return "home";
    }   
}

和應用程序配置中的設置

<aop:aspectj-autoproxy/>

<bean id="testAdvice" class="com.test.TestAdvice">
</bean>

<bean id="testAdvisor"
    class="org.springframework.aop.aspectj.AspectJExpressionPointcutAdvisor">
    <property name="advice" ref="testAdvice" />
    <property name="expression" value="execution(* *.home(..))" />
</bean>

和實際的建議

public class TestAdvice implements AfterReturningAdvice {

    protected final Log logger = LogFactory.getLog(getClass());

    public void afterReturning(Object returnValue, Method method, Object[] args,
            Object target) throws Throwable {
        logger.info("Called after returning advice!");
    }
}

甚至有可能對帶注釋的控制器提出建議嗎? 我正在使用 Spring 2.5。

可以在帶注釋的控制器上獲得建議。

我假設您希望在使用@Controller注釋的類中執行所有方法后提供建議。

這是一個例子:

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class ControllerAspect {

    @Pointcut("within(@org.springframework.stereotype.Controller *)")
    public void controllerBean() {}

    @Pointcut("execution(* *(..))")
    public void methodPointcut() {}

    @AfterReturning("controllerBean() && methodPointcut() ")
    public void afterMethodInControllerClass() {
        System.out.println("after advice..");
    }
}

如果你想使用帶有AspectJ語法的Spring AOP,你還需要一個像這樣的配置文件:

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

    <bean id="controllerAspect" class="controller.ControllerAspect" />

    <aop:aspectj-autoproxy>
        <aop:include name="controllerAspect" />
    </aop:aspectj-autoproxy>
</beans>

注意:使用Spring AOP,Spring容器只會編織Spring bean。 如果@Controller對象不是Spring bean,則必須使用AspectJ編織。

我有同樣的問題,在Repository的建議工作,但Controller的建議不是。 最后我找到了解決方案。 簡而言之,您需要確保在Servlet上下文中加載AOP定義,而不是在不同的上下文中加載。

在我的例子中,我的Spring AOP定義在tools-config.xml定義。 從這里移動后

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring/tools-config.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

到這里,

<servlet>
    <servlet-name>petclinic</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/mvc-core-config.xml, classpath:spring/tools-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

對Controller的建議正在發揮作用。

對於MVC控制器,完成您嘗試執行的操作的首選方法是使用攔截器。 http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-handlermapping-interceptor

@Aspect
@Component
public class HttpTraceAspect {
     
    // step1: interceptor all method in given package and sub packages
    @Pointcut("within(com.abc.xxx.admin.v2.controller..*)")
    public void pointCut1() {
    }

    @Pointcut("within(com.abc.xxx.admin.v1.old.controller..*)")
    public void pointCut2() {
    }

    @Around("pointCut1() || pointCut2()")
    public Object intercept(ProceedingJoinPoint pjp) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) pjp.getSignature();
        Method method = methodSignature.getMethod();

        HttpServletRequest request = HttpUtils.getHttpRequest();
        // step2: only intercept http method entry
        if (request == null || !isHttpMethodEntry(method)) {
            return pjp.proceed();
        }

        Object result = null;
        try {
            result = pjp.proceed();
            log.info("http trace, reqParams->{}, uri->{}, user->{}, response->{}",
                    toJSONString(pjp.getArgs()), request.getRequestURI(), getLoginUsername(), toJSONString(result));
            return result;
        } catch (Throwable t) {
            log.warn("http error, reqParams->{}, uri->{}, user->{}",
                    toJSONString(pjp.getArgs()), request.getRequestURI(), getLoginUsername(), t);
            throw t;
        }
    }

    private boolean isHttpMethodEntry(Method method) {
        if (method.getDeclaredAnnotations() != null) {
            for (Annotation annotation : method.getDeclaredAnnotations()) {
                if (annotation.annotationType().getName().startsWith("org.springframework.web.bind.annotation.")) {
                    return true;
                }
            }
        }
        return false;
    }

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM