【Spring5】AOP
3 AOP
面向切面程式設計,利用AOP可以對業務的各個邏輯進行隔離,從而使得業務邏輯各部分的耦合度之間降低,提高程式的可重用性,同時提高開發的效率。
目的:不通過修改原始碼,在主幹功能上增加新功能
AOP底層原理
1.動態代理實現類方法增強
(1)有介面的情況:通過JDK方式建立介面實現類的代理物件
public class JDKProxy { public static void main(String[] args) { Class[] interfaces = {UserDao.class}; UserDaoImpl userDao = new UserDaoImpl(); // 建立介面實現類的代理物件 // 代理的含義:不需要下面的介面實現類直接實現介面,而是通過代理的方式實現介面 // UserDao userDao1 = new UserDaoImpl(); // newProxyInstance返回介面實現類,第一個引數為當前類的類載入器,第二個引數是要實現介面的class陣列,第三個引數為增強邏輯後的介面實現類的代理類 UserDao userDao1 = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); System.out.println(userDao1.add(1, 1)); } }
代理的含義:不需要下面的介面實現類直接實現介面,而是通過代理的方式實現介面
UserDao userDao1 = new UserDaoImpl();
UserDao userDao1 = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
newProxyInstance返回介面實現類,第一個引數為當前類的類載入器,第二個引數是要實現介面的class陣列,第三個引數為增強邏輯後的介面實現類的代理類
編寫增強邏輯的介面實現類的代理類
obj表示代理物件的被代理方
class UserDaoProxy implements InvocationHandler { private Object obj; UserDaoProxy(Object obj) { this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("方法執行前"); Object res = method.invoke(obj, args); System.out.println(res); System.out.println("方法執行後"); return res; } }
(2)沒有介面的情況:通過CGLIB建立當前類的子類的代理物件
![](file://D:\資料\學習筆記\Java\Spring\1.png?msec=1649505122752)
AOP操作術語
1 連線點:類中可以被增強的方法
2 切入點:實際被真正增強的方法
3 通知(增強):實際增強的邏輯部分稱為通知(增強)
前置通知:
後置通知:
環繞通知:
異常通知:try-catch
最終通知:finally
4 切面
切面是一個動作:把通知應用到切入點的過程
AOP操作:基於AsepectJ實現AOP
AsepectJ不是Spring的組成部分,獨立於AOP框架,通常一起使用進行AOP操作。
兩種形式:基於xml配置檔案方式、基於註解方式
匯入jar包
spring-aspects-5.2.6.RELEASE.jar
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
切入點表示式
作用:知道哪個類的哪個方法應該增強
語法結構:execution([許可權修飾符][返回型別][類全路徑][方法名稱] ( [引數列表] ) )
*表示所有
步驟
①建立類和增強類
②進行通知的配置,開啟註解元件掃描
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
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.hikaru"></context:component-scan>
③新增建立類和增強類物件的註解,並在增強類上添加註解Aspect
@Component
public class User {
public void add() {
System.out.println("add...");
}
}
@Component
@Aspect
public class UserProxy {
}
④在Spring配置檔案中開啟生成代理物件
<!--開啟Aspect生成代理物件-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
⑤配置不同型別的通知
@Component
@Aspect
public class UserProxy {
@Before(value = "execution(* com.hikaru.User.add())")
public void before() {
System.out.println("before...");
}
@After(value = "execution(* com.hikaru.User.add(..))")
public void after() {
System.out.println("after...");
}
@AfterReturning(value = "execution(* com.hikaru.User.add(..))")
public void afterReturn() {
System.out.println("after return...");
}
@AfterThrowing(value = "execution(* com.hikaru.User.add(..))")
public void afterThrowing() {
System.out.println("afterThrowing...");
}
@Around(value = "execution(* com.hikaru.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("環繞之前");
proceedingJoinPoint.proceed();
System.out.println("環繞之後");
}
}
環繞之前
before...
add...
環繞之後
after...
after return...
After與AfterReturning的區別:
After無論有沒有異常都會輸出,AfterReturning只有沒有異常正常返回時才會輸出。
異常時的結果:
環繞之前
before...
after...
afterThrowing...
公共切入點抽取:重用切入點定義
在增強類中:
@Pointcut(value = "execution(* com.hikaru.User.add())")
public void PointDemo() {
}
通知中使用公共切入點
@Before(value = "PointDemo()")
public void before() {
System.out.println("before...");
}
有多個增強類對同一個類的同一個方法進行增強,應設定類優先順序
在增強類上添加註解@Order(數字特徵值),值越小表示優先順序越高
使用xml實現AOP操作
略
使用配置類代替配置檔案開啟Aspect生成代理物件,實現完全註解開發
@Configuration
@ComponentScan(value = {"com.hikaru"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class SpringConfig {
}
@Test
public void test() {
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
User user = context.getBean("user", User.class);
user.add();
}