在Spring中使用AspectJ實現AOP


 在spring中使用aspectj有2種方式:

  • xml配置
  • 注解配置(推薦)

 

這2種方式需要添加的jar包都一樣(待修改):

  • spring-aop.RELEASE.jar
  • aspectjweaver.jar

 

 

在spring中使用aspectj,不需要添加aspectjrt.jar,也不需要專門的ajc編譯器,使用javac編譯即可。

 

 


 

 

xml配置方式

(1)目標接口、目標類

新建包com.chy.dao,包下新建接口UserDao、實現類UserDaoImpl:

public interface UserDao {
    public void addUser();
    public void deleteUser();
}
public class UserDaoImpl implements UserDao{
    @Override
    public void addUser() {
        System.out.println("正在添加用戶...");
    }

    @Override
    public void deleteUser() {
        System.out.println("正在刪除用戶...");
    }
}

 

 

(2)切面

新建包com.chy.aspect,包下新建類UserDaoAspect:

public class UserDaoAspect {
    //前置通知要調用的方法
    public void before(){
        System.out.println("正在執行前置通知...");
    }

    //后置通知要調用的方法
    public void after(){
        System.out.println("正在執行后置通知...");
    }

    //返回通知要調用的方法
    public void afterReturning(Object obj){
        System.out.println("正在執行返回通知...");
        System.out.println("目標方法的返回值是:"+obj);
    }

    // 異常通知要調用的方法
    public void afterThrowing(JoinPoint point,Exception e){
        System.out.println("異常信息:"+e.getMessage());
    }
}

 

 

(3)xml配置

<?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!--目標對象-->
    <bean name="userDaoImpl" class="com.chy.dao.UserDaoImpl" />

    <!--切面-->
    <bean name="userDaoAspect" class="com.chy.aspect.UserDaoAspect" />

    <!--AOP配置-->
    <aop:config>
        <!--全局切入點,所有切面都可以引用。配置切入點只能用id,不能用name -->
<!--    <aop:pointcut id="pointCut" expression="execution(* com.chy.dao.UserDaoImpl.*(..))" />     -->
        
        <!--一個<aop:aspect>配置一個切面-->
        <aop:aspect ref="userDaoAspect">
            <!--局部切入點,只能在此切面中引用-->
            <aop:pointcut id="pointCut" expression="execution(* com.chy.dao.UserDao.*(..))" />
            
            <!--前置通知-->
            <aop:before method="before" pointcut-ref="pointCut" />
            <!--可以引用切入點,也可以現配-->
<!--        <aop:before method="before" pointcut="execution(* com.chy.dao.UserDao.*(..))"/>     -->
            
            <!--后置通知-->
            <aop:after method="after" pointcut-ref="pointCut" />
            
            <!--返回通知-->
            <!--如果要使用目標方法的返回值,可以用returning要將目標方法的返回值傳遞給返回通知要調用的方法的哪個形參-->
            <aop:after-returning method="afterReturning" pointcut-ref="pointCut" returning="obj"/>
            
            <!--異常通知-->
            <!--如果要使用捕獲的異常對象,可以用throwing指定要將異常對象傳遞給哪個形參-->
            <aop:after-throwing method="afterThrowing" pointcut-ref="pointCut" throwing="e"/>
            
        </aop:aspect>
        
    </aop:config>
    
</beans>

5種通知對應的方法都可以傳遞JoinPoint型的參數,不用傳遞實參,只有目標方法的返回值、捕獲的異常需要傳實參。

returning是返回通知的特有屬性,throwing是異常通知的特有屬性。

 

 

環繞通知

環繞通知與其它通知有重疊,通常不與其它通知一起使用。

    // 環繞通知
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //前增強
        System.out.println("正在執行前增強...");
        //調用目標方法
        Object object=proceedingJoinPoint.proceed();
        //后增強
        System.out.println("正在執行后增強...");
        return object;
    }
            <!--環繞通知-->
            <!--ProceedingJoinPoint是JoinPoint的子類,不必手動傳參-->
            <aop:around method="around" pointcut-ref="pointCut" />    

 

 


 

 

 注解配置方式

(1)目標接口、目標類

public interface UserDao {
    public void addUser();
    public void deleteUser();
}
@Repository
public class UserDaoImpl implements UserDao{
    @Override
    public void addUser() {
        System.out.println("正在添加用戶...");
    }

    @Override
    public void deleteUser() {
        System.out.println("正在刪除用戶...");
    }
}

 

 

 (2)切面

@Component
@Aspect
public class UserDaoAspect {
    //配置切入點
    @Pointcut("execution(* com.chy.dao.UserDao.*(..))")
    private void pointCut(){}
    
    /*
    前置通知
    @Before(value="pointCut()"),只有一個屬性時可以只寫屬性值
    @Before("execution(* com.chy.dao.UserDao.*(..))"),屬性值可以引用切入點,也可以現配
     */
    @Before("pointCut()")
    public void before(){
        System.out.println("正在執行前置通知...");
    }

    //后置通知
    @After("pointCut()")
    public void after(){
        System.out.println("正在執行后置通知...");
    }

    //返回通知。可傳遞目標方法的返回值。
    @AfterReturning(value = "pointCut()",returning = "obj" )
    public void afterReturning(Object obj){
        System.out.println("正在執行返回通知...");
        System.out.println("目標方法的返回值是:"+obj);
    }

    // 異常通知。可傳遞異常對象。
    @AfterThrowing(value = "pointCut()",throwing = "e")
    public void afterThrowing(JoinPoint point,Exception e){
        System.out.println("異常信息:"+e.getMessage());
    }   
}

 

環繞通知:

     // 環繞通知
    @Around("pointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //前增強
        System.out.println("正在執行前增強...");
        //調用目標方法
        Object object=proceedingJoinPoint.proceed();
        //后增強
        System.out.println("正在執行后增強...");
        return object;
    }

 

 

(3)xml配置

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

    <!--使用包掃描,要掃描多個包時用逗號分隔-->
    <context:component-scan base-package="com.chy.dao,com.chy.aspect" />

    <!--啟用AspectJ的注解-->
    <aop:aspectj-autoproxy />
</beans>

 

使用注解十分方便,xml文件也更加簡潔,推薦。

 

 


 

 

使用

不管是xml方式,還是注解方式,使用時都是一樣的:

 

1)如果目標類實現了接口,不管切入點配置為接口、還是實現類:

execution(* com.chy.dao.UserDao.*(..))
execution(* com.chy.dao.UserDaoImpl.*(..))

使用時都只能使用接口(代理的是接口,不是具體的實現類):

    UserDao userDao=applicationContext.getBean("userDaoImpl", UserDao.class);
    userDao.addUser();

紅色標出的兩處都只能使用接口。

 

 

(2)如果目標類沒有實現接口,那切入點只能配置為目標類:

execution(* com.chy.dao.UserDaoImpl.*(..))

使用時自然只能使用目標類:

    UserDaoImpl userDao=applicationContext.getBean("userDaoImpl", UserDaoImpl.class);
    userDao.addUser();    

 

 

調用方法時會自動增強。

 

 


 

 

AOP常見術語

  •  Joinpoint (連接點):目標類中的所有方法
  • Pointcut(切入點):目標類中被增強的方法。有時候我們只增強目標類的部分方法。
  • Weaving(織入):把增強應用到目標對象創建代理對象的過程。spring aop采用動態代理織入,aspectj采用在編譯期、類裝載期織入。

 


免責聲明!

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



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