Spring aop: 通過注解實現對controller的aop,出現的問題


前提1:web.xml中:

     <servlet>
		<servlet-name>Spring-mvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/DispatcherServlet.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>Spring-mvc</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>

  

前提2:DispatcherServlet.xml中(另外就是幾個interceptor)

前提3: 后文描述的情況,在<aop:aspectj-autoproxy proxy-target-class="true"/>與<aop:aspectj-autoproxy proxy-target-class="false"/>兩種前提下,結果毫無差別。

    <context:component-scan base-package="com"></context:component-scan>	
	<mvc:annotation-driven />
	<aop:aspectj-autoproxy />

前提4:controller為com.BaseController,通過<context:component-scan base-package="com"></context:component-scan>生成

 

@Component
@Aspect
public class aopDefault { private long beginTime; @Pointcut("execution(* org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(..))") private void aspect(){}//定義一個切入點  @Pointcut("execution(* com.BaseController.*(..))") private void _aspect(){}//定義一個切入點  @Before("execution(* com.BaseController.*(..))")//定義前置通知 public void doBefore(){ beginTime = System.currentTimeMillis(); System.out.println("doBefore"); } @AfterReturning("execution(* com.BaseController.*(..))")//定義后置通知 public void doAfter(JoinPoint joinpoint){ String className = joinpoint.getTarget().getClass().getName(); String method = joinpoint.getSignature().getName(); long endTime = System.currentTimeMillis(); long duration= endTime-beginTime; System.out.println("doAfter"); System.out.println("Method: "+className+"."+method); System.out.println("Elapsed time : "+duration + "ms"); System.out.println(""); } //doAround注解方法1 @Around("aspect()") public void doAround(){ System.out.println("doAround_1"); } //doAround注解方法2 @Around("_aspect()") public void _doAround(){ System.out.println("doAround_2"); } //doAround注解方法3 @Around("execution(* org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(..))") public void _doAround_(){ System.out.println("doAround_3"); } }

結果

控制台(顯然,“doAround注解方法1” 和 “doAround注解方法3” 完全不起作用,而Before,AfterReturning都OK,說明

("execution(* org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(..))")

這玩意兒,反正在我這是死活沒有一點兒用,再說一遍proxy-target-class="true"還是"false"都沒用):

doAround_2
doAfter
Method: com.BaseController.login
Elapsed time : 1466612786129ms

頁面部分結果(結果為error,就算將“返回值json”這一條件去除,也得不到任何返回值):

ajax.js:51 200
ajax.js:52 4 ajax.js:53 parsererror ajax代碼為 $.ajax({ url:"login.do", type:"post", dataType:"json", data:{userName:username, userPwd:pwd}, error: function(XMLHttpRequest, textStatus, errorThrown) { console.log(XMLHttpRequest.status); console.log(XMLHttpRequest.readyState); console.log(textStatus); }, success: function(json){ ... } }); 

6月23日補充(之前的結論太糙了。。。):

@Around("execution(* com.BaseController.*(..))")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
   Object retVal = pjp.proceed();
   System.out.println("doAround_1");
   return retVal;
}

@Around里,應該引入org.aspectj.lang.ProceedingJoinPoint,讓其procced()並將其返回,否則被“切”的controller方法倒是也能繼續進行,就是返回值為null(症狀跟上文描述的一樣,@Before不運行,@AfterReturning能正常運行)。。。。繼續琢磨。。。。。

正常的運行順序,@Before -》 @Around -》 @AfterReturning

寫法:

@Pointcut("execution(* com.BaseController.*(..))")
private void aspect(){}//定義一個切入點

@Before("aspect()") ....  

@Around("aspect()") 引入ProceedingJoinPoint,並.proceed(),返回 ....  

@AfterReturning("aspect()") ....  

 

 

6月27日補充:

        @RequestMapping(...)
    @ResponseBody
    @ControllerPointcut(str = ...) 
    public String initParams(HttpSession session){...} 
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ControllerPointcut {
    ...
}
@Component
@Aspect
public class ElapsedTimeAOP {
    
    private long beginTime;
    
    @Pointcut("@annotation(com.annotation.ControllerPointcut)")
    private void controller(){}//定義一個切入點 
    ...
}

鑒於剛學了annotation,這里定義一個annotation,在@pointcut里用以上形式做定義,然后到controller類里按需標注在方法前,即可以對該方法做aop,這樣可以減少aop定義代碼中的耦合,擴展起來還比較方便。


btw,抱歉寫的可能很讓人頭暈,水平有限。

 

這是參考的帖子:

http://itindex.net/detail/50710-springaop-controller-service/

http://yjian84.iteye.com/blog/1920787

http://phoenixfu.iteye.com/blog/2037598

http://www.oschina.net/question/222929_124314?fromerr=BICW0JoJ

http://usherlight.iteye.com/blog/1306111




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM