Spring框架簡介⑧

Milky-way發表於2018-08-08

AOP, 面向切面程式設計

 Aspect, 對橫切性關注點的一種抽象(簡而言之, 上面講到的動態代理就是一種橫切面)

相對而言, 類是對物體的一種抽象, 而切面是對橫切性關注點的一種抽象

JoinPoint(連線點): 要攔截的方法

PointCut(切點): 連線點的集合

Advice(通知): 在連線點前後或異常情況發生時做的事情, 如前置通知/後置通知/返回通知/異常通知/環繞通知

 

引包: 連結:https://pan.baidu.com/s/1lyoSeLmkkFJurBF_4GFH4g 密碼:hyz8

 

1 註解方式配置切面

    ①前置通知(@Before)

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="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/aop
           http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

    <!-- 開啟切面驅動(註解方式) -->
	<aop:aspectj-autoproxy/>
	
	<bean id="userService" class="com.rl.spring.service.impl.UserServiceImpl"></bean>
</beans>

配置切面類PermAspect(新增註解@Aspect):

package com.rl.spring.aspect;

import org.aspectj.lang.annotation.Aspect;

@Aspect
public class PermAspect {

    
}

配置PermAspect類裡面的切點和通知

package com.rl.spring.aspect;

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

@Aspect
public class PermAspect {

    /**
     * 第一個*: 代表任意返回值, 如果具體返回值 如: java.lang.String
     * 第二個*: 代表任意類
     * 第三個*: 代表任意方法
     * 第一個..: 代表service包下所有類和子包下的所有類
     * 第二個..: 代表方法的引數
     * 
     * 配置完成後 該方法即可攔截service及其子包下的任何類 任何返回值 任何方法以及任何引數
     */
    @Pointcut("execution(* com.rl.spring.service..*.*(..))")
    public void anyMethod() {
        
    }
    
    /**
     * 前置通知
     */
    @Before("anyMethod()")
    public void preAdive() {
        System.out.println("前置通知執行了...");
    }
}

需要先配置PermAspect類的bean

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="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/aop
           http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

    <!-- 開啟切面驅動(註解方式) -->
	<aop:aspectj-autoproxy/>
	
	<!-- 配置切面bean -->
	<bean id="permAspect" class="com.rl.spring.aspect.PermAspect"></bean>
	
	<bean id="userService" class="com.rl.spring.service.impl.UserServiceImpl"></bean>
</beans>

測試一下:

測試程式碼:

package com.rl.spring.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.rl.spring.service.UserService;

@RunWith(value=SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:ApplicationContext.xml"})
public class TestSpring {
	
    @Autowired
    UserService userService;
    
    @Test
    public void test() {
        userService.save();
    }
}

測試結果:

 

傳參的方式:

UserServiceImpl:

package com.rl.spring.service.impl;

import com.rl.spring.model.User;
import com.rl.spring.service.UserService;
public class UserServiceImpl implements UserService {

    private User user;
    
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public void save(User user) {
        System.out.println("儲存使用者..."+user);
    }

    @Override
    public void update() {
        System.out.println("修改使用者...");
    }
}

PermAspect:

package com.rl.spring.aspect;

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

import com.rl.spring.model.User;

@Aspect
public class PermAspect {

    /**
     * 配置切面方法
     * 
     * 第一個*: 代表任意返回值, 如果具體返回值 如: java.lang.String
     * 第二個*: 代表任意類
     * 第三個*: 代表任意方法
     * 第一個..: 代表service包下所有類和子包下的所有類
     * 第二個..: 代表方法的引數
     * 
     * 配置完成後 該方法即可攔截service及其子包下的任何類 任何返回值 任何方法以及任何引數
     */
    @Pointcut("execution(* com.rl.spring.service..*.*(..))")
    public void anyMethod() {
        
    }
    
    /**
     * 前置通知
     * anyMethod(): 指定切面方法
     * args(*): 指定傳參, * 為引數名, 在這裡args的引數名稱必須和方法引數的名稱相同 在此例中必須為user
     *          如果有多個引數, 則直接用逗號隔開即可 
     */
    @Before("anyMethod()&&args(user)")
    public void preAdive(User user) {
        System.out.println(user);
        //可以做一些操作
        user.setUsername("火星");
        System.out.println("前置通知執行了...");
    }
}

測試程式碼:

package com.rl.spring.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.rl.spring.model.User;
import com.rl.spring.service.UserService;

@RunWith(value=SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:ApplicationContext.xml"})
public class TestSpring {
	
    @Autowired
    UserService userService;
    
    @Test
    public void test() {
        User user = new User();
        user.setUserId(1);
        user.setUsername("lijialin");
        user.setPassword("123");
        userService.save(user);
    }
}

測試結果:

    ②後置通知(@After)

將配置檔案中的bean改為新建的PermAspect1

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="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/aop
           http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

    <!-- 開啟切面驅動(註解方式) -->
	<aop:aspectj-autoproxy/>
	
	<!-- 配置切面bean -->
	<bean id="permAspect" class="com.rl.spring.aspect.PermAspect1"></bean>
	
	<bean id="userService" class="com.rl.spring.service.impl.UserServiceImpl"></bean>
</beans>

PermAspect1

package com.rl.spring.aspect;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;

import com.rl.spring.model.User;

@Aspect
public class PermAspect1 {

    @Pointcut("execution(* com.rl.spring.service..*.*(..))")
    public void anyMethod() {
        
    }
    
    @After(value="anyMethod()")
    public void postAdvice() {
        System.out.println("執行後置通知...");
    }
}

測試程式碼:

package com.rl.spring.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.rl.spring.model.User;
import com.rl.spring.service.UserService;

@RunWith(value=SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:ApplicationContext.xml"})
public class TestSpring {
	
    @Autowired
    UserService userService;
    
    @Test
    public void test() {
        User user = new User();
        user.setUserId(1);
        user.setUsername("lijialin");
        user.setPassword("123");
        userService.save(user);
    }
    
    @Test
    public void test1() {
        userService.save();
    }
}

 

    ③返回通知(@AfterReturning)

返回通知程式碼:

package com.rl.spring.aspect;

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

import com.rl.spring.model.User;

@Aspect
public class PermAspect1 {

    @Pointcut("execution(* com.rl.spring.service..*.*(..))")
    public void anyMethod() {
        
    }
    
    
    
    /**
     * @AfterReturning: 返回通知的註解, 在返回通知裡面可以對業務方法的返回值做最後的統一加工處理
     * pointcut: 指定返回通知的切點
     * returning: 指定返回值和返回通知的方法的引數名稱要一致
     */
    @AfterReturning(pointcut="anyMethod()", returning="user")
    public void returnAdvice(User user) {
        user.setUsername("lijialin");//統一加工處理
        System.out.println("執行返回通知...");
    }
}

測試程式碼:

package com.rl.spring.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.rl.spring.model.User;
import com.rl.spring.service.UserService;

@RunWith(value=SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:ApplicationContext.xml"})
public class TestSpring {
	
    @Autowired
    UserService userService;
    
    
    
    @Test
    public void test2() {
        User user = userService.queryById(1);
        System.out.println("最終返回的user: "+user);
    }
}

輸出結果:

    ④例外通知(異常通知) @ AfterThrowing 主要用於執行期的監控, 異常時丟擲處理

在UserServiceImpl方法中設定一個異常1/0

異常通知程式碼:

package com.rl.spring.aspect;

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

import com.rl.spring.model.User;

@Aspect
public class PermAspect1 {

    @Pointcut("execution(* com.rl.spring.service..*.*(..))")
    public void anyMethod() {
        
    }
    
    
    
    @AfterThrowing(pointcut="anyMethod()", throwing="ex")
    public void exceptionAdvice(Exception ex) {
        System.out.println("執行例外通知...");
        ex.printStackTrace();
    }
}

測試程式碼:

package com.rl.spring.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.rl.spring.model.User;
import com.rl.spring.service.UserService;

@RunWith(value=SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:ApplicationContext.xml"})
public class TestSpring {
	
    @Autowired
    UserService userService;
   
    
    @Test
    public void test1() {
        userService.save();
    }
    
}

結果輸出:

 

    ⑤環繞通知(@Around 用的最多, 可以實現前置通知 後置通知 返回通知 例外通知的所有功能)

環繞通知程式碼:

package com.rl.spring.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import com.rl.spring.model.User;

@Aspect
public class PermAspect2 {

    @Pointcut("execution(* com.rl.spring.service..*.*(..))")
    public void anyMethod() {
        
    }
    
    /**
     * @Around: 環繞通知的註解, 指定切點
     * ProceedingJoinPoint: 正在執行的連線點, 正在執行攔截的方法的抽象
     * @throws Throwable 
     */
    @Around("anyMethod()")
    public Object doAroundAdvice(ProceedingJoinPoint jp) throws Throwable {
        Object[] args = jp.getArgs();//獲得引數
        System.out.println("環繞通知前--前置通知..."+args[0]);//本次示例引數只有一個, 取索引0
        
        //環繞通知的執行方法, 如果使用無參 則傳遞預設引數 返回值就是業務方法的返回值
//        Object obj = jp.proceed();//讓方法繼續走下去
        Object obj = jp.proceed(args);//此引數可以修改後再傳遞過去, 這樣就跟原先的引數值不一樣的了 但本例中沒改, 直接傳回去
        User user = (User) obj;
        user.setUsername("lijialin");
        System.out.println("環繞通知後--後置通知..."+"  返回值: "+obj);
        return obj;
    }
}

測試程式碼:

package com.rl.spring.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.rl.spring.model.User;
import com.rl.spring.service.UserService;

@RunWith(value=SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:ApplicationContext.xml"})
public class TestSpring {
	
    @Autowired
    UserService userService;
    
   
    
    @Test
    public void test3() {
        User user = userService.queryById(1);
        System.out.println(user);//也能將返回值輸出
    }
}

利用環繞通知配置許可權

環繞通知程式碼:

package com.rl.spring.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

import com.rl.spring.model.User;
import com.rl.spring.service.impl.UserServiceImpl;

@Aspect
public class PermAspect2 {
    
    @Pointcut("execution(* com.rl.spring.service..*.*(..))")
    public void anyMethod() {
        
    }
    
    
    @Around("anyMethod()")
    public Object doAroundAdvice(ProceedingJoinPoint jp) throws Throwable {
        
        UserServiceImpl us = (UserServiceImpl) jp.getTarget();
        User user = us.getUser();
        Object obj = null;
        if(user != null) {
            obj = jp.proceed();
        }else {
            System.out.println("您還沒有登入呢!");
        }
        return obj;
    }
}

測試程式碼:

package com.rl.spring.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.rl.spring.model.User;
import com.rl.spring.service.UserService;

@RunWith(value=SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:ApplicationContext.xml"})
public class TestSpring {
	
    @Autowired
    UserService userService;
   
    
    @Test
    public void test4() {
        userService.save(new User());//這裡即使是new了一個User 在業務類裡面的User還是為null
    }
}

輸出結果:

 

2 配置檔案方式配置切面

 

前置通知:

配置檔案:

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="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/aop
           http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

	<!-- 配置切面bean -->
	<bean id="permAspect" class="com.rl.spring.aspect.PermAspect"></bean>
	
	<bean id="userService" class="com.rl.spring.service.impl.UserServiceImpl"></bean>
	
	<!-- 配置aop -->
	<aop:config>
	<!-- 配置切點 -->
	   <aop:pointcut expression="execution(* com.rl.spring.service..*.*(..))" id="mycut"/>
	   <!-- 配置切面 -->
	   <aop:aspect ref="permAspect">
	   <!-- 指定切面中的方法為前置通知 -->
	       <aop:before method="preAdvice" pointcut-ref="mycut"/>
	   </aop:aspect>
	</aop:config>
</beans>

切面程式碼:

package com.rl.spring.aspect;

import org.aspectj.lang.JoinPoint;

public class PermAspect {

    /**
     * 無需註解配置了, 已經在配置檔案中定義好了
     */
    public void preAdvice(JoinPoint jp) {
        Object[] args = jp.getArgs();
        System.out.println("執行前置通知..."+"引數: "+args[0]);
    }
}

測試程式碼:

package com.rl.spring.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.rl.spring.model.User;
import com.rl.spring.service.UserService;

@RunWith(value=SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:ApplicationContext.xml"})
public class TestSpring {
	
    @Autowired
    UserService userService;
    
    @Test
    public void test() {
        User user = new User();
        user.setUserId(1);
        user.setUsername("lijialin");
        user.setPassword("123");
        userService.save(user);
    }
    
}

輸出結果:

後置通知:

與前置通知同理:

輸出結果:

返回通知:

返回通知程式碼:

package com.rl.spring.aspect;

import org.aspectj.lang.JoinPoint;

import com.rl.spring.model.User;

public class PermAspect {

   
    
    public void returnAdvice(JoinPoint jp, Object returnval) {
        if(returnval instanceof User) {
            User user = (User) returnval;
            user.setUsername("lijialin");
        }
        System.out.println("返回通知..."+"返回的值: "+returnval);
    }
}

配置檔案:

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="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/aop
           http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

	<!-- 配置切面bean -->
	<bean id="permAspect" class="com.rl.spring.aspect.PermAspect"></bean>
	
	<bean id="userService" class="com.rl.spring.service.impl.UserServiceImpl"></bean>
	
	<!-- 配置aop -->
	<aop:config>
	<!-- 配置切點 -->
	   <aop:pointcut expression="execution(* com.rl.spring.service..*.*(..))" id="mycut"/>
	   <!-- 配置切面 -->
	   <aop:aspect ref="permAspect">
	   <!-- 指定切面中的方法為前置通知 -->
	       <aop:before method="preAdvice" pointcut-ref="mycut"/>
	       <aop:after method="afterAdvice" pointcut-ref="mycut"/>
	       <aop:after-returning method="returnAdvice" pointcut-ref="mycut" returning="returnval"/>
	   </aop:aspect>
	</aop:config>
</beans>

測試程式碼:

package com.rl.spring.test;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.rl.spring.model.User;
import com.rl.spring.service.UserService;

@RunWith(value=SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= {"classpath:ApplicationContext.xml"})
public class TestSpring {
	
    @Autowired
    UserService userService;
    
    @Test
    public void test1() {
        User user = userService.queryById(1);
        System.out.println(user);
    }
}

輸出結果:

例外通知:

例外通知程式碼:

package com.rl.spring.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

import com.rl.spring.model.User;

public class PermAspect {

    /**
     * 無需註解配置了, 已經在配置檔案中定義好了
     */
    public void preAdvice(JoinPoint jp) {
        Object[] args = jp.getArgs();
        if(args.length>0)
        System.out.println("執行前置通知..."+"引數: "+args[0]);
    }
    
    public void afterAdvice(JoinPoint jp) {
        Object[] args = jp.getArgs();
        if(args.length>0)
        System.out.println("執行後置通知..."+"引數: "+args[0]);
    }
    
    public void returnAdvice(JoinPoint jp, Object returnval) {
        if(returnval instanceof User) {
            User user = (User) returnval;
            user.setUsername("lijialin");
        }
        System.out.println("返回通知..."+"返回的值: "+returnval);
    }
    
    public void exceptionAdvice(JoinPoint jp, Exception ex) {
        System.out.println("例外通知...");
        ex.printStackTrace();
    }
    
   
}

配置檔案:

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="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/aop
           http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

	<!-- 配置切面bean -->
	<bean id="permAspect" class="com.rl.spring.aspect.PermAspect"></bean>
	
	<bean id="userService" class="com.rl.spring.service.impl.UserServiceImpl"></bean>
	
	<!-- 配置aop -->
	<aop:config>
	<!-- 配置切點 -->
	   <aop:pointcut expression="execution(* com.rl.spring.service..*.*(..))" id="mycut"/>
	   <!-- 配置切面 -->
	   <aop:aspect ref="permAspect">
	   <!-- 指定切面中的方法為前置通知 -->
	       <aop:before method="preAdvice" pointcut-ref="mycut"/>
	       <aop:after method="afterAdvice" pointcut-ref="mycut"/>
	       <aop:after-returning method="returnAdvice" pointcut-ref="mycut" returning="returnval"/>
	       <!-- 
	           throwing: 丟擲的異常變數名, 需要跟切面類裡面的變數匹配
	        -->
	       <aop:after-throwing method="exceptionAdvice" pointcut-ref="mycut" throwing="ex"/>
	      
	   </aop:aspect>
	</aop:config>
</beans>

 

結果輸出:

 

環繞通知:

環繞通知程式碼:

package com.rl.spring.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

import com.rl.spring.model.User;

public class PermAspect {

    /**
     * 無需註解配置了, 已經在配置檔案中定義好了
     */
    public void preAdvice(JoinPoint jp) {
        Object[] args = jp.getArgs();
        if(args.length>0)
        System.out.println("執行前置通知..."+"引數: "+args[0]);
    }
    
    public void afterAdvice(JoinPoint jp) {
        Object[] args = jp.getArgs();
        if(args.length>0)
        System.out.println("執行後置通知..."+"引數: "+args[0]);
    }
    
    public void returnAdvice(JoinPoint jp, Object returnval) {
        if(returnval instanceof User) {
            User user = (User) returnval;
            user.setUsername("lijialin");
        }
        System.out.println("返回通知..."+"返回的值: "+returnval);
    }
    
    public void exceptionAdvice(JoinPoint jp, Exception ex) {
        System.out.println("例外通知...");
        ex.printStackTrace();
    }
    
    public Object aroundAdvice(ProceedingJoinPoint jp) {
        Object[] objs = jp.getArgs();
        Object obj = null;
        System.out.println("環繞通知之前置通知...");
        if(objs.length>0) {
            System.out.println("執行環繞通知..."+"引數: "+objs[0]);
            try {
                obj = jp.proceed();
                System.out.println("環繞通知之後置通知...");
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
        return obj;
    }
}

配置檔案:

<?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:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="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/aop
           http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">

	<!-- 配置切面bean -->
	<bean id="permAspect" class="com.rl.spring.aspect.PermAspect"></bean>
	
	<bean id="userService" class="com.rl.spring.service.impl.UserServiceImpl"></bean>
	
	<!-- 配置aop -->
	<aop:config>
	<!-- 配置切點 -->
	   <aop:pointcut expression="execution(* com.rl.spring.service..*.*(..))" id="mycut"/>
	   <!-- 配置切面 -->
	   <aop:aspect ref="permAspect">
	   <!-- 指定切面中的方法為前置通知 -->
	       <aop:before method="preAdvice" pointcut-ref="mycut"/>
	       <aop:after method="afterAdvice" pointcut-ref="mycut"/>
	       <aop:after-returning method="returnAdvice" pointcut-ref="mycut" returning="returnval"/>
	       <!-- 
	           throwing: 丟擲的異常變數名, 需要跟切面類裡面的變數匹配
	        -->
	       <aop:after-throwing method="exceptionAdvice" pointcut-ref="mycut" throwing="ex"/>
	       <aop:around method="aroundAdvice" pointcut-ref="mycut"/>
	   </aop:aspect>
	</aop:config>
</beans>

結果輸出:

相關文章