Spring框架之Spring AOP
阿新 • • 發佈:2017-09-20
權限 保持 eth before app spring win 應該 ctc 一、基於註解管理的AOP
1、Spring配置文件
<!-- 配置自動掃描包,自動掃描Bean組件,切面類 -->
<context:component-scan base-package="com.zhoujian.spring.anno,com.zhoujian.spring.test">
<!-- <context:include-filter type="annotation" expression="org.aspectj.lang.annotation.Aspect"/> -->
</context:component-scan>
<!-- 啟動@Aspectj支持 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
2、切面類
package com.zhoujian.spring.aspect;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
/**
* 如何聲明一個切面類: 首先是放入IOC容器進行管理, 其次是需要Aspect進行修飾
*
*/
public class AuthAspectClass {
@Before(value = "execution(* com.zhoujian.spring.anno.*.*(..))")
// @Before("execution(* com.zhoujian.spring.test.*.*(..))")
public void before() {
System.out.println("模擬進行權限檢查...");
}
@After("execution(* com.zhoujian.spring.anno.*.*(..))")
public void after() {
/**
* after增強處理,不管目標方法是如何結束的,該方法會在目標方法結束之後被織入
* 如果對同一目標方法進行了after和afterReturning增強處理且目標方法正常執行結束,
* 此時會先織入after增強處理,之後才是afterReturning增強處理,
* 如果目標方法非正常結束, 那麽只會在目標方法結束之後,織入after增強處理,
* 如果目標方法的非正常結束拋出了異常,伴兒會在目標方法結束之後,先織入after增強處理,
* 之後才會織入afterThrowing增強處理
*/
System.out.println("關閉當前事務...");
}
@AfterReturning(returning = "returnVal", value = "execution(* com.zhoujian.spring.anno.*.*(..))")
public void afterReturning(Object returnVal) {
System.out.println("目標方法的返回值:" + returnVal);
System.out.println("只有目標方法正常執行完成後,才會執行AfterReturning...");
}
@AfterThrowing(throwing="exception",value="execution(void com.zhoujian.spring.anno.HelloImpl.getSub())")
public void afterThrowing(Exception exception){
System.out.println("只有執行com.zhoujian.spring.anno.HelloImpl.getSub() 該方法 ,才會進行增強");
System.out.println("目標方法拋出的異常為: " + exception.getMessage());
System.out.println("模擬Advice進行異常處理...");
}
@Around("execution(public int com.zhoujian.spring.anno.HelloImpl.total(..))")
public Object around(ProceedingJoinPoint joinPoint){
/**
* Around增強處理是一個很強大,但是通常需要在一個線程安全的環境使用(比如在proceed方法調用前後需要共享數據)
*/
Object result = null;
try {
Object[] args = {6,3,"4"};
/**
* 在這裏傳入一個Object數組,可以替換目標方法中的實參,偷天換日
* 但是,傳入參數的個數和類型應該與目標方法保持一致
* 如果個數少於目標方法參數個數或者類型不匹配都會拋出異常
* 如果是 個數多余目標方法參數個數,那麽會從數組下標0開始往後取出相同個數作為實參,此時如果取出的數組元素
* 類型與目標方法類型不匹配,那麽也會拋出異常
*/
System.out.println(joinPoint.getThis());
System.out.println(joinPoint.getTarget());
result = joinPoint.proceed(args);
} catch (Throwable e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(result);
/**
* return 返回值時 也可以進行目標方法返回值的修改,偷天換日
*/
return result;
}
}
3、業務類
package com.zhoujian.spring.anno;
import org.springframework.stereotype.Component;
@Component
public class HelloImpl implements Hello {
@Override
public void foo() {
System.out.println("執行Hello組件的 foo()方法...");
}
@Override
public int addUser(String name, String pass) {
System.out.println("執行Hello組件的addUser()方法添加用戶: " + name);
return 10;
}
public void getSub(){
System.out.println("執行Hello組件的getSub()方法...");
int num = 12;
if(num % 2 == 0){
throw new NullPointerException("假裝我是一個空指針異常...");
}
}
}
4、測試方法
@Test
public void beanTest(){
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
HelloImpl he = ac.getBean(HelloImpl.class);
// System.out.println(he.getClass());
he.foo();
he.addUser("張三", "123456");
he.getSub();
}
5、定義切入點
package com.zhoujian.spring.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LogAspectClass {
/**
* 使用 @Pointcut 定義一個切入點,方法返回類型必須是void
* 因為這僅僅只是一個簽名形式的方法,為了聲明切入點的名稱,不需要方法體,所以方法體也為空
* 如果需要在其他的切面類中進行引用時,必須遵循Java的權限訪問控制標準,
* 采用類名為前綴: value="LogAspectClass.myPointcut()"
* 或者 pointcut="LogAspectClass.myPointcut()"
*/
@Pointcut("execution(* com.zhoujian.spring.anno.*.*(..))")
public void myPointcut(){}
@Before(value="myPointcut()")
public void beforeLog(){
System.out.println("使用定義好的切入點");
}
}
二、基於XML管理的AOP
1、Spring配置文件
<!-- 切面類 -->
<bean id="logAspectClassWithXML" class="com.zhoujian.spring.aspect.LogAspectClassWithXML"></bean>
<!-- helloImpl 實現了 Hello 接口 -->
<bean id="helloImpl" class="com.zhoujian.spring.anno.HelloImpl"></bean>
<!-- helloImpl2 是一個單實體類,沒有繼承任何類和 實現任何接口 -->
<bean id="helloImpl2" class="com.zhoujian.spring.anno.HelloImpl2"></bean>
<!-- fordCarChild 繼承了FordCar類-->
<bean id="fordCarChild" class="com.zhoujian.spring.anno.FordCarChild"></bean>
<!-- AOP 配置 -->
<aop:config>
<aop:aspect id="logAspect" ref="logAspectClassWithXML" order="1">
<aop:before method="beforeLog" pointcut="execution(* com.zhoujian.spring.anno.*.*(..))"/>
</aop:aspect>
</aop:config>
2、切面類和相關實體類
Hello接口
package com.zhoujian.spring.anno;
public interface Hello {
public void foo();
public int addUser(String name, String pass);
}
Hello實現類 HelloImpl
package com.zhoujian.spring.anno;
public class HelloImpl implements Hello {
@Override
public void foo() {
System.out.println("執行Hello組件的 foo()方法...");
}
@Override
public int addUser(String name, String pass) {
System.out.println("執行Hello組件的addUser()方法添加用戶: " + name);
return 10;
}
public void getSub(){
System.out.println("執行Hello組件的getSub()方法...");
int num = 12;
if(num % 2 == 0){
throw new NullPointerException("假裝我是一個空指針異常...");
}
}
public int total(int a, int b){
int total = a + b;
return total;
}
}
單實體類 HelloImpl2
package com.zhoujian.spring.anno;
public class HelloImpl2{
public void foo() {
System.out.println("執行Hello組件的 foo()方法...");
}
public int addUser(String name, String pass) {
System.out.println("執行Hello組件的addUser()方法添加用戶: " + name);
return 10;
}
public void getSub(){
System.out.println("執行Hello組件的getSub()方法...");
int num = 12;
if(num % 2 == 0){
throw new NullPointerException("假裝我是一個空指針異常...");
}
}
public int total(int a, int b){
int total = a + b;
return total;
}
}
切面類 LogAspectClassWithXML
package com.zhoujian.spring.aspect;
import org.apache.catalina.tribes.util.Arrays;
import org.aspectj.lang.JoinPoint;
public class LogAspectClassWithXML {
public void beforeLog(JoinPoint point){
System.out.println("Before:增強的目標方法名為:" + point.getSignature().getName());
System.out.println("Before:增強的目標方法的參數為:" + Arrays.toString(point.getArgs()));
System.out.println("Before:被織入增強的目標對象為:" + point.getTarget());
}
public void after(JoinPoint point) {
/**
* after增強處理,不管目標方法是如何結束的,該方法會在目標方法結束之後被織入
* 如果對同一目標方法進行了after和afterReturning增強處理且目標方法正常執行結束,
* 此時會先織入after增強處理,之後才是afterReturning增強處理,
* 如果目標方法非正常結束, 那麽只會在目標方法結束之後,織入after增強處理,
* 如果目標方法的非正常結束拋出了異常,那麽會在目標方法結束之後,先織入after增強處理,
* 之後才會織入afterThrowing增強處理
*/
System.out.println("After: 目標方法結束後釋放資源...");
System.out.println("After:增強的目標方法名為:" + point.getSignature().getName());
System.out.println("After:增強的目標方法的參數為:" + Arrays.toString(point.getArgs()));
System.out.println("After:被織入增強的目標對象為:" + point.getTarget());
}
public void afterReturning(JoinPoint point, Object returnVal) {
System.out.println("AfterReturning: 獲取目標方法的返回值" + returnVal);
System.out.println("AfterReturning:增強的目標方法名為:" + point.getSignature().getName());
System.out.println("AfterReturning:增強的目標方法的參數為:" + Arrays.toString(point.getArgs()));
System.out.println("AfterReturning:被織入增強的目標對象為:" + point.getTarget());
}
public void afterThrowing(JoinPoint point, Exception exception, String name, String age){
System.out.println("AfterThrowing: 獲取到目標方法拋出的異常" + exception.getMessage());
System.out.println("AfterThrowing:增強的目標方法名為:" + point.getSignature().getName());
System.out.println("AfterThrowing:增強的目標方法的參數為:" + Arrays.toString(point.getArgs()));
System.out.println("AfterThrowing:被織入增強的目標對象為:" + point.getTarget());
}
}
3、測試類 AspectWithXMLTest
package com.zhoujian.spring.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.zhoujian.spring.anno.HelloImpl2;
public class AspectWithXMLTest {
@Test
public void test() {
ApplicationContext ac = new ClassPathXmlApplicationContext("aspectWithXML.xml");
System.out.println(ac.getBean("helloImpl").getClass().getName());
/**
* helloImpl 實體類實現了一個接口,所以其代理類的獲取必須使用其實現的接口進行獲取,不然會發生類型轉換異常
*/
com.zhoujian.spring.anno.Hello hel = (com.zhoujian.spring.anno.Hello) ac.getBean("helloImpl");
hel.foo();
}
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("aspectWithXML.xml");
/**
* 單實體類:即沒有繼承和實現任何類和接口的實體類, 在獲取其代理對象的時候,直接獲取就行了
* 即使目標類繼承了一個或者多個類,獲取時正常獲取即可,用其父類進行獲取也行
*/
System.out.println(ac.getBean("helloImpl").getClass().getName());
HelloImpl2 hel = (HelloImpl2) ac.getBean("helloImpl2");
hel.foo();
}
}
註:Spring AOP 由 IOC 容器進行生成和管理,當進行IOC容器創建的時候,IOC容器會掃描切入點表達式所包含的所有包中所有類,並為所有類創建代理對象
如果目標類沒有實現任何的接口,Spring將會是cglib方式創建代理對象;
如果目標類實現了一個或多個接口或者,那麽Spring將會采用JDK動態代理創建代理類(此時代理類的獲取必須使用接口類型接收)
使用Spring版本:spring-framework-4.3.10.RELEASE-dist
Spring框架之Spring AOP