注解、原生Spring、SchemaBased三種方式實現(xiàn)AOP代碼案例
一、注解配置AOP
Spring可以使用注解代替配置文件配置切面:
1. 開啟注解支持
在xml中開啟AOP注解支持
以下是bean1.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 掃描包 -->
<context:component-scan base-package="com.example"></context:component-scan>
<!-- 開啟注解配置Aop -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>2. 在類和方法加入注解
在通知類上方加入注解 @Aspect:配置切面
在通知方法上方加入注解
- @Before:前置通知
- @AfterReturning:后置通知
- @AfterThrowing:異常通知
- @After:最終通知
- @Around:環(huán)繞通知
MyAspectAdvice通知類
package com.example.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class MyAspectJAdvice {
// 后置通知
@AfterReturning("execution(* com.example.dao.UserDao.*(..))")
public void myAfterReturning(JoinPoint joinPoint){
System.out.println("切點方法名:"+joinPoint.getSignature().getName());
System.out.println("目標(biāo)對象:"+joinPoint.getTarget());
System.out.println("打印日志···"+joinPoint.getSignature().getName()+"方法被執(zhí)行了!");
}
// 前置通知
@Before("execution(* com.example.dao.UserDao.*(..))")
public void myBefore(){
System.out.println("前置通知···");
}
// 異常通知
@AfterThrowing(value = "execution(* com.example.dao.UserDao.*(..))",throwing = "e")
public void myAfterThrowing(Exception e){
System.out.println("異常通知···");
System.out.println(e.getMessage());
}
// 最終通知
@After("execution(* com.example.dao.UserDao.*(..))")
public void myAfter(){
System.out.println("最終通知···");
}
// 環(huán)繞通知
@Around("execution(* com.example.dao.UserDao.*(..))")
public Object myAround(ProceedingJoinPoint point) throws Throwable {
System.out.println("環(huán)繞前···");
// 執(zhí)行方法
Object obj = point.proceed();
System.out.println("環(huán)繞后···");
return obj;
}
}3. 測試
測試方法
// 測試注解開發(fā)AOP
@Test
public void testAdd2(){
ApplicationContext ac = new ClassPathXmlApplicationContext("bean1.xml");
UserDao userDao = (UserDao) ac.getBean("userDao");
//userDao.update();
userDao.delete();
}測試結(jié)果(無異常):

使用update方法測試結(jié)果(有異常):

可以看到環(huán)繞后沒有打印,因為此時碰到異常終止了程序
4. 為一個類下的所有方法統(tǒng)一配置切點
如何為一個類下的所有方法統(tǒng)一配置切點:
在通知類中添加方法配置切點
// 添加方法配置切點
@Pointcut("execution(* com.example.dao.UserDao.*(..))")
public void pointcut(){
}在通知方法上使用定義好的切點,就是把注解括號里面得內(nèi)容替換成 "pointCut()" 即可。
二、原生Spring實現(xiàn)AOP
除了AspectJ,Spring支持原生方式實現(xiàn)AOP。但是要注意的是原生方式實現(xiàn)AOP只有四種通知類型:前置通知、后置通知、環(huán)繞通知,異常通知。少了最終通知。
1. 引入依賴
<!-- AOP -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.3.13</version>
</dependency>2. 編寫SpringAOP通知類
Spring原生方式實現(xiàn)AOP時,只支持四種通知類型:
| 通知類型 | 實現(xiàn)接口 |
|---|---|
| 前置通知 | MethodBeforeAdvice |
| 后置通知 | AfterReturningAdvice |
| 異常通知 | ThrowsAdvice |
| 環(huán)繞通知 | MethodInterceptor |
package com.example.aspect;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.MethodBeforeAdvice;
import org.springframework.aop.ThrowsAdvice;
import java.lang.reflect.Method;
public class SpringAop implements MethodBeforeAdvice, AfterReturningAdvice, ThrowsAdvice, MethodInterceptor {
/**
* 環(huán)繞通知
* @param invocation 目標(biāo)方法
* @return
* @throws Throwable
*/
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("環(huán)繞前");
Object proceed = invocation.proceed();
System.out.println("環(huán)繞后");
return proceed;
}
/**
* 后置通知
* @param returnValue 目標(biāo)方法的返回值
* @param method 目標(biāo)方法
* @param args 目標(biāo)方法的參數(shù)列表
* @param target 目標(biāo)對象
* @throws Throwable
*/
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("后置通知");
}
/**
* 前置通知
* @param method 目標(biāo)方法
* @param args 目標(biāo)方法的參數(shù)列表
* @param target 目標(biāo)對象
* @throws Throwable
*/
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("前置通知");
}
/**
* 異常通知
* @param e 異常對象
*/
public void afterThrowing(Exception e){
System.out.println("發(fā)生異常了!");
}
}3. 編寫配置類bean2.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.example"></context:component-scan>
<!-- 通知對象 -->
<bean id="springAop" class="com.example.aspect.SpringAop"/>
<!-- 配置代理對象 -->
<bean id="userDaoProxy"class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 配置目標(biāo)對象 -->
<property name="target" ref="userDao"/>
<!-- 配置通知 -->
<property name="interceptorNames">
<list>
<value>springAop</value>
</list>
</property>
<!-- 代理對象的生成方式 true:使用CGLib false:使用原生JDK生成 -->
<property name="proxyTargetClass" value="true"/>
<!-- bug -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
</bean>
</beans>4 測試
測試類UserDaoTest2
import com.example.dao.UserDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class userDaoTest2 {
// 原生AOP測試
@Test
public void testAdd(){
ApplicationContext ac = new ClassPathXmlApplicationContext("bean2.xml");
UserDao userDao = (UserDao) ac.getBean("userDaoProxy");
userDao.update();
}
}測試結(jié)果

OK,這里有個驚喜,如果敲到這里同學(xué),就知道了
其實標(biāo)簽?zāi)莻€bug,是因為原生方法配置類要加上那個標(biāo)簽才可以識別,否則會報一個錯誤。
三、SchemaBased實現(xiàn)AOP
SchemaBased(基礎(chǔ)模式)配置方式是指使用Spring原生方式定義通知,而使用AspectJ框架配置切面。因此這里通知類和上面一樣,看上面的即可。
1. 配置切面
aop3.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<context:component-scan base-package="com.example"></context:component-scan>
<!-- 通知對象 -->
<bean id="springAop2" class="com.example.aspect.SpringAop"/>
<!-- 配置切面 -->
<aop:config>
<!-- 配置切點 -->
<aop:pointcut id="myPointcut" expression="execution(* com.example.dao.UserDao.*(..))"/>
<!-- 配置切面:advice-ref:通知對象 pointcut-ref:切點 -->
<aop:advisor advice-ref="springAop2" pointcut-ref="myPointcut"/>
</aop:config>
</beans>2. 測試
測試方法
// 使用AspectJ框架配置切面測試
@Test
public void t6(){
ApplicationContext ac = new ClassPathXmlApplicationContext("aop3.xml");
UserDao userDao = (UserDao) ac.getBean("userDao");
userDao.add();
}測試結(jié)果

OK,這里的輸出應(yīng)該是我上面定義的不夠完美,有些可能重復(fù)定義了,所以這里就重復(fù)輸出了一些東西
到此這篇關(guān)于注解、原生Spring、SchemaBased三種方式實現(xiàn)AOP代碼案例的文章就介紹到這了,更多相關(guān)注解、原生Spring、SchemaBased實現(xiàn)AOP內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java8如何用Stream查List對象某屬性是否有重復(fù)
這篇文章主要介紹了java8如何用Stream查List對象某屬性是否有重復(fù)的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
SpringBoot中@Autowired爆紅原理分析及解決
這篇文章主要介紹了SpringBoot中@Autowired爆紅原理分析及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-05-05
Spring data jpa @Query update的坑及解決
這篇文章主要介紹了Spring data jpa @Query update的坑及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-02-02

