springmvc 在controller層使用aop切面編程

第一 編寫切點


首先我們在Springmvc的controller層中定義一個測試用的切點


package com.lin.controller;


import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@RequestMapping("/sys/login")
@Controller
public class LoginController {

	@RequestMapping(value="/t")
	@ResponseBody
	public Map<String,Object> test(HttpServletRequest request, HttpServletResponse response){
		Map<String,Object> map=new HashMap<String, Object>();
		System.out.println("我是切點");
		return map;
	}
}

第二 定義切面


Spring 藉助AspectJ的切點表達式語言來定義Spring切面。

下面我們來看一個切點表達式,這個表達式能夠設置當test(..)方法執行時觸發通知的調用。


我們使用execution()指示器選擇LoginController的test()方法。方法表達式以“*”號開始,表明我們不關心方法返回值的類型。然後,我們指定了全限定類名和方法名。對於方法參數列表,我們使用兩個點好(..)表明切點要選擇任意的 test()方法,無論該方法的參數是什麼。


編寫切面POJO類

package com.lin.common.aop;

import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Component
@Aspect
public class Audience {
   
	@Before("execution(* com.lin.controller.LoginController.test(..))")
	public void before(){
	    RequestAttributes ra = RequestContextHolder.getRequestAttributes();
            ServletRequestAttributes sra = (ServletRequestAttributes) ra;
            HttpServletRequest request = sra.getRequest();  //獲取request 可以從中獲取參數或cookie
		System.out.println("我是切面");
	}	
}
@Component (把普通pojo實例化到spring容器中,相當於配置文件中的<bean id="" class=""/>)

Audience類使用@Aspect註解進行了標註。該註解表明Audience不僅僅是一個POJO,還是一個切面。Audience類中的方法都使用註解來定義切面的具體行爲。


Spring使用AspectJ註解來聲明通知方法

@Before  通知方法還會在目標方法調用之前執行

@Around 通知方法會將目標方法封裝起來

@AfterThrowing 通知方法會在目標方法拋出異常後調用

@AfterReturning 通知方法會在目標方法返回後調用

@After 通知方法會在目標方法返回或拋出異常後調用


第三 在XML中,通過Spring的aop命名空間啓用AspectJ代理

在Springmvc中使用AOP我們需要將啓用代理放在Spring-mvc.xml中,否則代理不生效。


原因(摘自其他博客,該部分內容原地址:http://blog.csdn.net/my_nice_life/article/details/52910718):

(部分借鑑)CGLIB代理配置在了applicationContext.xml 核心配置文件中,該配置文件會被ContextLoaderListenerclass加載,Spring會創建一個WebApplicationContext上下文,稱爲父上下文(父容器) ,保存在ServletContext中,key爲WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值。

而spring-mvc.xml是DispatcherServlet,可以同時配置多個,每個 DispatcherServlet有一個自己的上下文對象(WebApplicationContext),稱爲子上下文(子容器),子上下文可以訪問父上下文中的內容,但父上下文不能訪問子上下文中的內容。 它也保存在 ServletContext中,key是”org.springframework.web.servlet.FrameworkServlet.CONTEXT”+Servlet名稱

當spring加在父容器的時候就會去找切入點,但是這個時候切入的controller是在子容器中的,父容器是無法訪問子容器,所以就攔截不到。如果將上述的配置文件放到spring-mvc.xml中,那麼問題就解決了。我已經測試可以通過URL訪問觸發切點了。


配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:p="http://www.springframework.org/schema/p"  
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:context="http://www.springframework.org/schema/context"
  xmlns:mvc="http://www.springframework.org/schema/mvc"
  <!-- Spring aop 命名空間-->
 xmlns:aop="http://www.springframework.org/schema/aop"
 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
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd
    http://www.springframework.org/schema/mvc
    http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
       
    <!-- 掃描controller(controller層注入) -->
   <context:component-scan base-package="com.lin.controller"/>
    <!-- 開啓spring對註解驅動的支持 -->
    <mvc:annotation-driven/>
   <!-- 啓動AspectJ自動代理 --> 
   <aop:aspectj-autoproxy proxy-target-class="true"/>
 </beans>


測試結果





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章