本文參考實(shí)驗(yàn)樓教程:https://www.shiyanlou.com/courses/578/learning/?id=1940
AspectJ是基于注解(Annotation)的,所以需要JDK5.0版本以上。本文實(shí)驗(yàn)環(huán)境延用之Spring Aop:一、四種advice 的實(shí)驗(yàn)環(huán)境。
AspectJ支持的注解類(lèi)型如下:
- @Before
- @After
- @AfterReturning
- @AfterThrowing
- @Around
1、準(zhǔn)備工作
首先定義一個(gè)簡(jiǎn)單的bean,CustomerBo實(shí)現(xiàn)了ICustomerBo接口。ICustomerBo接口代碼如下:
package com.shiyanlou.spring.aop.aspectj;
/**
* Created by Administrator on 2019/11/2.
*/
public interface ICustomerBo {
void addCustomer();
void deleteCustomer();
String addCustomerReturnValue();
void addCustomerThrowException() throws Exception;
void addCustomerAround(String name);
}
CustomerBo.java代碼如下:
package com.shiyanlou.spring.aop.aspectj;
/**
* Created by Administrator on 2019/11/2.
*/
public class CustomerBo implements ICustomerBo {
@Override
public void addCustomer() {
System.out.println("addCustomer() is running...");
}
@Override
public void deleteCustomer() {
System.out.println("deleteCustomer() is running...");
}
@Override
public String addCustomerReturnValue() {
System.out.println("addCustomerReturnValue() is running...");
return "abc";
}
@Override
public void addCustomerThrowException() throws Exception {
System.out.println("addCustomerThrowException() is running...");
throw new Exception("Generic Error!");
}
@Override
public void addCustomerAround(String name) {
System.out.println("addCustomerAround() is running, args: " + name);
}
}
2、簡(jiǎn)單的AspectJ,Advice和Pointcut結(jié)合在一塊的
首先在沒(méi)有引入AspectJ之前,Advice和Pointcut是混在一塊的,步驟如下:
- 創(chuàng)建一個(gè)Aspect類(lèi)
- 配置Spring配置文件
由于接下來(lái)要使用aspectj的jar包,首先要添加maven依賴(lài),需要在pom.xml中添加:
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.9.2</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.2</version>
</dependency>
注:這在之前已經(jīng)添加過(guò)了,這里這是說(shuō)明他們的用途。
創(chuàng)建AspectJ類(lèi),LoggingAspect.java如下:
package com.shiyanlou.spring.aop.aspectj;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
* Created by Administrator on 2019/11/2.
*/
@Aspect
public class LoggingAspect {
@Before("execution(public * com.shiyanlou.spring.aop.aspectj.CustomerBo.addCustomer(..))")
public void logBefore(JoinPoint joinPoint){
System.out.println("logBefore() is running...");
System.out.println("wei:" + joinPoint.getSignature().getName());
System.out.println("***********");
}
@After("execution(public * com.shiyanlou.spring.aop.aspectj.CustomerBo.deleteCustomer(..))")
public void logAfter(JoinPoint joinPoint){
System.out.println("logAfter() is running...");
System.out.println("wei:" + joinPoint.getSignature().getName());
System.out.println("***********");
}
}
解釋?zhuān)?/p>
- 必須使用
@Aspect在LoggingAspect之前聲明,以便被框架掃描到; - 此例中Advice和Poincut結(jié)合在一起,
LoggingAspect類(lèi)中的logBefore和logAfter即為Advice,要注入的代碼,即它們上方的代碼為Pointcut表達(dá)式,即定義了切入點(diǎn)。上例中@Before中代碼表示在執(zhí)行com.shiyanlou.spring.aop.aspectj.CustomerBo的addCustomer方法前注入logBefore代碼; - 需要在LoggingAspect類(lèi)的方法前加上
@Before,@After等注釋?zhuān)?/li> -
execution(public * com.shiyanlou.spring.aop.aspectj.CustomerBo.addCustomer(..))是Aspect的Pointcut表達(dá)式:
*代表任意返回類(lèi)型- 后面定義要攔截的方法名(全路徑:包名.類(lèi)名.方法名)
(..)代表匹配參數(shù):任意多個(gè)任意類(lèi)型的參數(shù),若確認(rèn)沒(méi)有參數(shù)可以寫(xiě)();還可以用(*)代表任意一個(gè)類(lèi)型的參數(shù),(*,String)表示匹配兩個(gè)參數(shù),第一個(gè)任意類(lèi)型,第二個(gè)必須是String類(lèi)型。
- AspectJ表達(dá)式可以對(duì)整個(gè)包定義,例如:
execution(public * com.shiyanlou.spring.aop.aspectj.*.*(..))表示切入點(diǎn)是com.shiyanlou.spring.aop.aspectj整個(gè)包的所有類(lèi)的所有方法。
配置SpringAopAspectJ.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 http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy/>
<bean id="customerBo" class="com.shiyanlou.spring.aop.aspectj.CustomerBo"/>
<bean id="loggingAspect" class="com.shiyanlou.spring.aop.aspectj.LoggingAspect"/>
</beans>
<aop:aspectj-autoproxy/>代表啟動(dòng)AspectJ支持,這樣Spring會(huì)自動(dòng)尋找@Aspect注釋過(guò)的類(lèi),其他配置一致;
執(zhí)行App.java,如下:
package com.shiyanlou.spring;
import com.shiyanlou.spring.aop.advice.CustomerService;
import com.shiyanlou.spring.aop.aspectj.CustomerBo;
import com.shiyanlou.spring.aop.aspectj.ICustomerBo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* Hello world!
*
*/
public class App
{
private static ApplicationContext context;
public static void main( String[] args ) {
context = new ClassPathXmlApplicationContext("SpringAopAspectJ.xml");
ICustomerBo cust = (ICustomerBo) context.getBean("customerBo");
cust.addCustomer();
System.out.println("-----------------------");
cust.deleteCustomer();
}
}
執(zhí)行結(jié)果如下:
logBefore() is running...
wei:addCustomer
***********
addCustomer() is running...
-----------------------
deleteCustomer() is running...
logAfter() is running...
wei:deleteCustomer
***********
3、將Advice和Pointcut 分開(kāi)
需要三步驟:
- 創(chuàng)建Pointcut
- 創(chuàng)建Advice
- 配置Spring的配置文件
1)、定義Pointcut
創(chuàng)建PointcutsDefinitions.java,如下:
package com.shiyanlou.spring.aop.aspectj;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
/**
* Created by Administrator on 2019/11/2.
*/
@Aspect
public class PointcutsDefinitions {
@Pointcut("execution(public * com.shiyanlou.spring.aop.aspectj.CustomerBo.*(..))")
public void customreLog(){
}
}
解釋?zhuān)?/p>
- 類(lèi)聲明之前加上
@Aspect注釋?zhuān)槐楸豢蚣軖呙璧剑?/li> -
@Pointcut定義了切入點(diǎn)聲明,指定需要注入代碼的位置(即在哪個(gè)類(lèi)的哪個(gè)方法中注入額外代碼),上例中指定的切入點(diǎn)為CustomerBo.java類(lèi)中的所有方法;但是往往實(shí)際應(yīng)用中,我們需要切入的是一整個(gè)業(yè)務(wù)邏輯層(簡(jiǎn)單點(diǎn)說(shuō)就是某個(gè)包),例如@Pointcut("execution(public * com.shiyanlou.spring.aop.aspectj.*.*(..))"),表示的是com.shiyanlou.spring.aop.aspectj包中所有類(lèi)的所有方法。 - 方法
customreLog只是一個(gè)簽名,在Advice中可以用此簽名代替切入點(diǎn)表達(dá)式,多以不需要寫(xiě)方法體,只起到助記功能,例如此處代表操作CustomerBo類(lèi)中的切入點(diǎn)。
2)、修改LoggingAspect.java
package com.shiyanlou.spring.aop.aspectj;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
* Created by Administrator on 2019/11/2.
*/
@Aspect
public class LoggingAspect {
@Before("com.shiyanlou.spring.aop.aspectj.PointcutsDefinitions.customreLog()")
public void logBefore(JoinPoint joinPoint){
System.out.println("logBefore() is running...");
System.out.println("wei:" + joinPoint.getSignature().getName());
System.out.println("***********");
}
@After("com.shiyanlou.spring.aop.aspectj.PointcutsDefinitions.customreLog()")
public void logAfter(JoinPoint joinPoint){
System.out.println("logAfter() is running...");
System.out.println("wei:" + joinPoint.getSignature().getName());
System.out.println("***********");
}
}
解釋?zhuān)?/p>
@Before和@After注釋使用PointcutsDefinitions中的方法簽名代替Pointcut表達(dá)式找到相應(yīng)的切入點(diǎn), 即通過(guò)簽名找到PointcutsDefinitions方法customreLog前定義的Pointcut表達(dá)式;- 對(duì)于
PointcutsDefinitions來(lái)說(shuō),它的主要職責(zé)是定義Pointcut即切入點(diǎn),可以在其中定義多個(gè)切入點(diǎn),并且使用便于記憶的方法簽名表示;- 單獨(dú)定義Pointcut表達(dá)式的好處有,一是使用了有意義的方法名,二是Pointcut表達(dá)式可以被多個(gè)Advice共享,修改一處其他所有使用的地方均被修改。
3)、配置Spring配置文件
配置的SpringAopAspectJ.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 http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy/>
<bean id="customerBo" class="com.shiyanlou.spring.aop.aspectj.CustomerBo"/>
<bean id="loggingAspect" class="com.shiyanlou.spring.aop.aspectj.LoggingAspect"/>
</beans>
App.java不變,運(yùn)行如下:
logBefore() is running...
wei:addCustomer
***********
addCustomer() is running...
logAfter() is running...
wei:addCustomer
***********
-----------------------
logBefore() is running...
wei:deleteCustomer
***********
deleteCustomer() is running...
logAfter() is running...
wei:deleteCustomer
***********