spring 使用@AspectJ注解開發Spring AOP


 選擇切點

  Spring是方法級別的AOP框架,而我們主要也是以某個類的某個方法作為切點,用動態代理的理論來說,就是要攔截哪個方法織入對應AOP通知。
  代碼清單:打印角色接口
package com.ssm.chapter11.aop.service;

import com.ssm.chapter11.game.pojo.Role;

public interface RoleService {

    // public void printRole(Role role);

    public void printRole(Role role, int sort);

}

 

  代碼清單:RoleService實現類
package com.ssm.chapter11.aop.service.impl;

import org.springframework.stereotype.Component;
import com.ssm.chapter11.aop.service.RoleService;
import com.ssm.chapter11.game.pojo.Role;

@Component
public class RoleServiceImpl implements RoleService {

    // @Override
    // public void printRole(Role role) {
    //     System.out.println("{id: " + role.getId() + ", " + "role_name : " + role.getRoleName() + ", " + "note : " + role.getNote() + "}");
    // }

    public void printRole(Role role, int sort) {
        System.out.println("{id: " + role.getId() + ", " + "role_name : " + role.getRoleName() + ", " + "note : " + role.getNote() + "}");
        System.out.println(sort);
    }

}

 

  這個類沒什么特別的,只是這個時候如果把printRole作為AOP的切點,那么用動態代理的語言就是要為類RoleServi-ceImpl生成代理對象,然后攔截printRole方法,於是可以產生各種AOP通知方法。

創建切面

  選擇好了切點就可以創建切面了,對於動態代理的概念而言,它就如同一個攔截器,在Spring中只要使用@Aspect注解一個類,那么Spring IoC容器就會認為這是一個切面了
package com.ssm.chapter11.aop.aspect;

import com.ssm.chapter11.aop.verifier.RoleVerifier;
import com.ssm.chapter11.aop.verifier.impl.RoleVerifierImpl;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

@Aspect
public class RoleAspect {

    @DeclareParents(value = "com.ssm.chapter11.aop.service.impl.RoleServiceImpl+", defaultImpl = RoleVerifierImpl.class)
    public RoleVerifier roleVerifier;

    @Pointcut("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))")
    public void print() {
    }

    // @Before("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))")
    // @Before("execution(* com.ssm.chapter11.*.*.*.*.printRole(..)) && within(com.ssm.chapter11.aop.service.impl.*)")
    @Before("print()")
    // @Before("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..)) && args(role, sort)")
    public void before() {
        System.out.println("before ....");
    }

    @After("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))")
    public void after() {
        System.out.println("after ....");
    }

    @AfterReturning("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))")
    public void afterReturning() {
        System.out.println("afterReturning ....");
    }

    @AfterThrowing("execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))")
    public void afterThrowing() {
        System.out.println("afterThrowing ....");
    }

    @Around("print()")
    public void around(ProceedingJoinPoint jp) {
        System.out.println("around before ....");
        try {
            jp.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("around after ....");
    }

}

 

連接點

  Spring是如何判斷是否需要攔截方法的,畢竟並不是所有的方法都需要使用AOP編程,這就是一個連接點的問題。在注解中定義了execution的正則表達式,Spring是通過這個正則表達式判斷是否需要攔截你的方法的,這個表達式是:
  execution(* com.ssm.chapter11.aop.service.impl.RoleServiceImpl.printRole(..))
  依次對這個表達式做出分析。
  •execution:代表執行方法的時候會觸發。
  •*:代表任意返回類型的方法。
  •com.ssm.chapter11.aop.service.impl.RoleServiceImpl:代表類的全限定名。
  •printRole:被攔截方法名稱。
  •(..):任意的參數。
  顯然通過上面的描述,全限定名為com.ssm.chapter11.aop.service.impl.RoleServiceImpl的類的printRole方法被攔截了,這樣它就按照AOP通知的規則把方法織入流程中。

 



測試AOP

  代碼清單:配置Spring bean
package com.ssm.chapter11.aop.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import com.ssm.chapter11.aop.aspect.RoleAspect;

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.ssm.chapter11.aop")
public class AopConfig {

    @Bean
    public RoleAspect getRoleAspect() {
        return new RoleAspect();
    }

}

 

  Spring還提供了XML的方式,這里就需要使用AOP的命名空間了
<?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-4.0.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
        http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">

    <aop:aspectj-autoproxy/>
    <bean id="roleAspect" class="com.ssm.chapter11.aop.aspect.RoleAspect"/>
    <bean id="roleService" class="com.ssm.chapter11.aop.service.impl.RoleServiceImpl"/>

</beans>

 

  無論用XML還是用Java的配置,都能使Spring產生動態代理對象,從而組織切面,把各類通知織入到流程當中

  代碼清單:測試AOP流程
package com.ssm.chapter11.aop.main;

import com.ssm.chapter11.aop.verifier.RoleVerifier;
import com.ssm.chapter11.aop.verifier.impl.RoleVerifierImpl;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.ssm.chapter11.aop.config.AopConfig;
import com.ssm.chapter11.aop.service.RoleService;
import com.ssm.chapter11.game.pojo.Role;

public class Main {

    public static void main(String[] args) {

        ApplicationContext ctx = new AnnotationConfigApplicationContext(AopConfig.class);
        // 使用XML使用ClassPathXmlApplicationContext作為IoC容器
        // ApplicationContext ctx = new ClassPathXmlApplicationContext("ssm/chapter11/spring-cfg3.xml");
        RoleService roleService = ctx.getBean(RoleService.class);

        Role role = new Role();
        role.setId(1L);
        role.setRoleName("role_name_1");
        role.setNote("note_1");

        RoleVerifier roleVerifier = (RoleVerifier) roleService;
        if (roleVerifier.verify(role)) {
            roleService.printRole(role, 1);
        }
        System.out.println("####################");
        //測試異常通知
        // role = null;
        // roleService.printRole(role);
    }

}

 





免責聲明!

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



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