用v9做的網(wǎng)站上傳服務(wù)器杭州seo整站優(yōu)化
文章目錄
- 一、日志處理
- 二、事務(wù)控制
- 三、參數(shù)校驗(yàn)
- 四、自定義注解
- 五、AOP 方法失效問題
- 1. ApplicationContext
- 2. AopContext
- 3. 注入自身
- 六、附錄
- 1. 示例代碼
AOP 提供了一種面向切面操作的擴(kuò)展機(jī)制,通常這些操作是與業(yè)務(wù)無關(guān)的,在實(shí)際應(yīng)用中,可以實(shí)現(xiàn):日志處理、事務(wù)控制、參數(shù)校驗(yàn)和自定義注解等功能。
Spring AOP 的原理參閱:《Spring中的AOP和動(dòng)態(tài)代理》
一、日志處理
在調(diào)試程序時(shí),如果需要在執(zhí)行方法前打印方法參數(shù),或者在執(zhí)行方法后打印方法返回結(jié)果,可以使用切面來實(shí)現(xiàn)。
@Slf4j
@Aspect
@Component
public class LoggerAspect {@Around("execution(* cn.codeartist.spring.aop.sample.*.*(..))")public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {// 方法執(zhí)行前日志log.info("Method args: {}", joinPoint.getArgs());Object proceed = joinPoint.proceed();// 方法執(zhí)行后日志log.info("Method result: {}", proceed);return proceed;}
}
二、事務(wù)控制
Spring 提供的聲明式事務(wù)也是基于 AOP 來實(shí)現(xiàn)的,在需要添加事務(wù)的方法上面使用 @Transactional
注解。
@Service
public class DemoService {@Transactional(rollbackFor = Exception.class)public void insertBatch() {// 帶事務(wù)控制的業(yè)務(wù)操作}
}
三、參數(shù)校驗(yàn)
如果需要在方法執(zhí)行前對(duì)方法參數(shù)進(jìn)行校驗(yàn)時(shí),可以使用前置通知來獲取切入點(diǎn)方法的參數(shù),然后進(jìn)行校驗(yàn)。
@Slf4j
@Aspect
@Component
public class ValidatorAspect {@Before("execution(* cn.codeartist.spring.aop.sample.*.*(..))")public void doBefore(JoinPoint joinPoint) {// 方法執(zhí)行前校驗(yàn)參數(shù)Object[] args = joinPoint.getArgs();}
}
四、自定義注解
因?yàn)?AOP 可以攔截到切入點(diǎn)方法,Spring 也支持通過注解的方式來定義切點(diǎn)表達(dá)式,所以可以通過 AOP 來實(shí)現(xiàn)自定義注解的功能。
例如,自定義一個(gè)注解來實(shí)現(xiàn)聲明式緩存,把方法的返回值進(jìn)行緩存。
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Cacheable {/*** 緩的Key*/String key();/*** 緩存過期時(shí)間*/long timeout() default 0L;/*** 緩存過期時(shí)間單位(默認(rèn):毫秒)*/TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}
然后定義一個(gè)切片來實(shí)現(xiàn)常規(guī)的緩存操作,先讀緩存,緩存不存在時(shí)執(zhí)行方法,然后把方法的返回結(jié)果進(jìn)行緩存。
@Aspect
@Component
public class AnnotationAspect {@Around("@annotation(cacheable)")public Object doAround(ProceedingJoinPoint joinPoint, Cacheable cacheable) throws Throwable {// 自定義緩存邏輯return joinPoint.proceed();}
}
五、AOP 方法失效問題
Spring AOP 的原理是在原有方法外面增加一層代理,所以在當(dāng)前類調(diào)用 AOP 方法時(shí),因?yàn)?this
指向的是當(dāng)前對(duì)象,而不是代理對(duì)象,所以 AOP 會(huì)失效。
@Service
public class DemoService {public void insert() {// 該方法事務(wù)會(huì)失效insertBatch();}@Transactional(rollbackFor = Exception.class)public void insertBatch() {// 帶事務(wù)控制的業(yè)務(wù)操作}
}
解決這個(gè)問題的常用方法有下面三種:
1. ApplicationContext
使用 ApplicationContext
來手動(dòng)獲取 Bean 對(duì)象,來調(diào)用 AOP 方法:
@Service
public class DemoService {@Autowiredprivate ApplicationContext applicationContext;public void insert() {DemoService demoService = applicationContext.getBean(DemoService.class);demoService.insertBatch();}@Transactional(rollbackFor = Exception.class)public void insertBatch() {// 帶事務(wù)控制的業(yè)務(wù)操作}
}
2. AopContext
使用 AopContext
工具類來獲取當(dāng)前對(duì)象的代理對(duì)象。
@Service
public class DemoService {public void insert() {((DemoService) AopContext.currentProxy()).insertBatch();}@Transactional(rollbackFor = Exception.class)public void insertBatch() {// 帶事務(wù)控制的業(yè)務(wù)操作}
}
3. 注入自身
使用 Spring 注入自身來調(diào)用 AOP 方法:
@Service
public class DemoService {@Autowiredprivate DemoService that;public void insert() {that.insertBatch();}@Transactional(rollbackFor = Exception.class)public void insertBatch() {// 帶事務(wù)控制的業(yè)務(wù)操作}
}
六、附錄
1. 示例代碼
Gitee 倉(cāng)庫(kù):https://gitee.com/code_artist/spring