1、AspectJ技術
因為在xml配置aop過程中太過繁瑣,aopalliance 中出現了一種AspectJ技術。
2、 Spring AOP支援的AspectJ切入點訓示符
切入點訓示符用來訓示切入點表達式目的,,在Spring AOP中目前隻有執行方法這一個連接配接點,Spring AOP支援的AspectJ切入點訓示符如下:execution:用于比對方法執行的連接配接點;
within:用于比對指定類型内的方法執行;
this:用于比對目前AOP代理對象類型的執行方法;注意是AOP代理對象的類型比對,這樣就可能包括引入接口也類型比對;
target:用于比對目前目标對象類型的執行方法;注意是目标對象的類型比對,這樣就不包括引入接口也類型比對;
args:用于比對目前執行的方法傳入的參數為指定類型的執行方法;
@within:用于比對是以持有指定注解類型内的方法;
@target:用于比對目前目标對象類型的執行方法,其中目标對象持有指定的注解;
@args:用于比對目前執行的方法傳入的參數持有指定注解的執行;
@annotation:用于比對目前執行方法持有指定注解的方法;
bean:Spring AOP擴充的,AspectJ沒有對于訓示符,用于比對特定名稱的Bean對象的執行方法;
reference pointcut:表示引用其他命名切入點,隻有@ApectJ風格支援,Schema風格不支援。
3、類型比對文法
首先讓我們來了解下AspectJ類型比對的通配符:*:比對任何數量字元;
…:比對任何數量字元的重複,如在類型模式中比對任何數量子包;而在方法參數模式中比對任何數量參數。
+:比對指定類型的子類型;僅能作為字尾放在類型模式後邊。
代碼:
java.lang.String 比對String類型;
java.*.String 比對java包下的任何“一級子包”下的String類型;
如比對java.lang.String,但不比對java.lang.ss.String
java..* 比對java包及任何子包下的任何類型;
如比對java.lang.String、java.lang.annotation.Annotation
java.lang.*ing 比對任何java.lang包下的以ing結尾的類型;
java.lang.Number+ 比對java.lang包下的任何Number的自類型;
如比對java.lang.Integer,也比對java.math.BigInteger
4、組合切入點表達式
AspectJ使用 且(&&)、或(||)、非(!)來組合切入點表達式。
在Schema風格下,由于在XML中使用“&&”需要使用轉義字元“&&”來代替之,是以很不友善,是以Spring ASP 提供了and、or、not來代替&&、||、!。
5、切入點使用示例
execution:使用“execution(方法表達式)”比對方法執行;
模式 | 描述 |
---|---|
public * *(…) | 任何公共方法的執行 |
* cn.javass…IPointcutService.*() | cn.javass包及所有子包下IPointcutService接口中的任何無參方法 |
* cn.javass….(…) | cn.javass包及所有子包下任何類的任何方法 |
6、AspectJ技術執行個體
- 通過注解配置切點(哪個方法需要被入侵)和通知(黑客)
- 自動生産代理對象
1)建立AppConfig.java
package com.lq.aspect;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration // 标示為配置類 相當于xml檔案
//掃描指定包下包含@Component注解的類,将這個類加入spring bean工程
@ComponentScan(value = { "com.lq.aspect", "com.lq.dao" })
@EnableAspectJAutoProxy // 啟動aspectJ注解aop
public class AppConfig {
}
- 建立@Aspect 切面類
package com.lq.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 org.springframework.stereotype.Component;
@Component
@Aspect
public class LogAspect {
/*
* 定義切點----需要增強的方法
*
*/
@Pointcut("execution(public int com.lq.dao.UserDapImpl.add(..))")
public void pointCut() {
}
// 環繞通知(循環通知/增強(黑客))
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("1.鑒權");
// 調用目标方法
Object[] args = joinPoint.getArgs();
args[0] = 22;
args[1] = 22;
Object result = joinPoint.proceed();
System.out.println("2.日志留痕");
return result;
}
}
3)實體類
package com.lq.dao;
import org.springframework.stereotype.Component;
@Component
public class UserDapImpl {
public int add(int a,int b) {
System.out.println("調用【未實作接口的】UserDaoImpl的add方法");
return a+b;
}
}
- 測試
package com.lq.proxy;
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.lq.aspect.AppConfig;
import com.lq.dao.UserDapImpl;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class)
public class AspectJTest {
@Autowired
UserDapImpl userDap;
@Test
public void testAdd() {
System.out.println(userDap.add(11, 22));
}
}
- 測試結果為:
九月 29, 2020 10:40:17 下午 org.springframework.test.context.support.AbstractTestContextBootstrapper getDefaultTestExecutionListenerClassNames
資訊: Loaded default TestExecutionListener class names from location [META-INF/spring.factories]: [org.springframework.test.context.web.ServletTestExecutionListener, org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener, org.springframework.test.context.support.DependencyInjectionTestExecutionListener, org.springframework.test.context.support.DirtiesContextTestExecutionListener, org.springframework.test.context.transaction.TransactionalTestExecutionListener, org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener]
九月 29, 2020 10:40:17 下午 org.springframework.test.context.support.AbstractTestContextBootstrapper getTestExecutionListeners
資訊: Using TestExecutionListeners: [org.springframework.test.context.support.DirtiesContextBeforeModesTestExe[email protected], org.springframework.test.context.support.DependencyInjectionTestExecutionListener@4e04a765, org.springframework.test.context.support.DirtiesContextTestExecutionListener@783e6358]
九月 29, 2020 10:40:18 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
資訊: Refreshing org.springframework.context.support.GenericApplicationContext@100fc185: startup date [Tue Sep 29 22:40:18 CST 2020]; root of context hierarchy
1.鑒權
調用【未實作接口的】UserDaoImpl的add方法
2.日志留痕
33