Spring AOP快速使用教學

2022-06-07 06:00:57

​ Spring是方法級別的AOP框架,我們主要也是以某個類的某個方法作為連線點,用動態代理的理論來說,就是要攔截哪個方法織入對應的AOP通知。為了更方便的測試我們首先建立一個介面

public interface RoleService {
    public void printRole(Role role);
}

然後建立一個實現類

@Component
public class RoleServiceImpl implements RoleService {
    public void printRole(Role role) {
        System.out.println(role.toString());
    }
}

​ 這個類沒啥特別,這個時候把printRole作為AOP的連線點,那麼用動態代理的語言就是要為類RoleServiceImpl生成代理物件,然後攔截printRole方法,可以用於產生各種AOP通知方法。

​ 接著我們來進行切面的建立,他如同一個攔截器,在Spring中只要使用@Aspect註解一個類,那麼Spring IOC 容器就會認為這是一個切面了。

@Aspect
public class RoleAspect {

    //在被代理物件的方法前呼叫 ,使用args來傳遞引數
    @Before("execution(* com.aop.RoleServiceImpl.printRole(..)) && args(role,sort)")
    public void before(Role role, int sort) {
        System.out.println("before...");
    }

    //在被代理物件的方法後呼叫
    @After("execution(* com.aop.RoleServiceImpl.printRole(..))")
    public void after() {
        System.out.println("after...");
    }

    //在被代理物件方法正常返回後呼叫
    @AfterReturning("execution(* com.aop.RoleServiceImpl.printRole(..))")
    public void afterRunning() {
        System.out.println("afterRunning");
    }

    //在被代理物件方法丟擲異常後使用
    @AfterThrowing("execution(* com.aop.RoleServiceImpl.printRole(..))")
    public void afterThrowing() {
        System.out.println("afterThrowing");
    }

    //將驗證角色物件是否為空的類加入到切面中
    //value=""表示對某類進行增強,defaultImpl表示預設的實現類
    @DeclareParents(value = "com.aop.RoleServiceImpl+", defaultImpl = RoleVerifierImpl.class)
    public RoleVerifier roleVerifier;
}

​ 此時連線點和切面我們都建立完成了,這個時候可以編寫程式碼來測試AOP的內容,首先要對Spring的Bean進行設定,採用註解Java設定。

@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com")
public class AppConfig {
    @Bean
    public RoleAspect getRoleAspect() {
        return new RoleAspect();
    }
}

測試AOP流程

public class Main {
    public static void main(String[] args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        RoleService roleService = (RoleService) ctx.getBean(RoleService.class);
        //使用剛才建立的RoleVerifier來進行檢測role物件是否為空
        RoleVerifier verifier = (RoleVerifier) ctx.getBean(RoleVerifier.class);

        Role role = new Role();
        role.setId(1L);
        role.setRoleName("張三");
        role.setRoleNote("張三的備註資訊");
        System.out.println("##測試結果");
        roleService.printRole(role);
        System.out.println("#####################");
        //測試異常通知
        role = null;
        roleService.printRole(role, 2);
    }
}
##測試結果
before...
Role{id=1, roleName='張三', roleNote='張三的備註資訊'}
1
afterRunning
after...
#####################
before...
afterThrowing  ##異常通知
after...
Exception in thread "main" java.lang.NullPointerException
	at com.aop.RoleServiceImpl.printRole(RoleServiceImpl.java:9)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)

很顯然切面的通知已經通過AOP織入約定的流程當中了,這時我們可以使用AOP來處理一些需要切面的場景了。