spring的面向切面編程坚嗜,即aop編程是有3種作用的:
- 日志記錄
- 安全驗證
- 數(shù)據(jù)庫事務(wù)管理
這里簡單的先講述下日志的記錄體現(xiàn)卷胯。
1.spring的aop配置有基于注解和xml2種,為了方便演示,這里用上次ssm搭建代碼來演示缎除,代碼地址https://gitee.com/cyy2csy/ssm。
(1)基于xml的spring aop配置
? ? 新建包Aspect总寻,在下面新建織入類LoggingAspect:
package com.cyy.maven.core.Aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
/**
* @Author: Cyy
* @Description: 織入類
* @Date:Created in 16:00 2018/7/22
*/
@Slf4j
public class LoggingAspect {
? ? public void beforeMethod(JoinPoint joinPoint){
? ? String methodName = joinPoint.getSignature().getName();
? ? ? ? Object [] args = joinPoint.getArgs();
? ? ? ?log.info("The method={} begins with={}",methodName,Arrays.asList(args));
? ? }
public void afterMethod(JoinPoint joinPoint){
? ? String methodName = joinPoint.getSignature().getName();
? ? log.info("The method={} ends",methodName);
? ? }
? public void afterReturning(JoinPoint joinPoint, Object result){
? ? String methodName = joinPoint.getSignature().getName();
? ? ? ?log.info("The method={},ends with={}",methodName,result);
? ? }
public void afterThrowing(JoinPoint joinPoint, Exception e){
? ? String methodName = joinPoint.getSignature().getName();
????? log.error("The method={},occurs excetion:={}",methodName,e);
? ? }
? public Object aroundMethod(ProceedingJoinPoint pjd){
? ? Object result =null;
? ? ? ? String methodName = pjd.getSignature().getName();
? ? ? ? try {
????????????//前置通知
? ? ? ? ? log.info("The method={},begins with={}", methodName, Arrays.asList(pjd.getArgs()));
? ? ? ? ? ? //執(zhí)行目標方法
? ? ? ? ? ? result = pjd.proceed();
? ? ? ? ? ? //返回通知
? ? ? ? ? log.info("The method={},ends with={}",methodName ,result);
? ? ? ? }catch (Throwable e) {
????????????//異常通知
? ? ? ? ? ?log.error("The method={},occurs exception:={}",methodName,e);
? ? ? ? ? ? throw new RuntimeException(e);
? ? ? ? }
//后置通知
? ? ? ?log.info("The method={},ends",methodName);
? ? ? ? return result;
? ? }
}
在spring的配置文件spring-context.xml中配置基于aop的事務(wù)增強梢为。
<bean id="loggingAspect" class="com.cyy.maven.core.Aspect.LoggingAspect"/>
<aop:config>
<aop:pointcut id="serviceOpearation" expression="execution(* com.cyy.maven.core.service.impl.*.*(..))"/>
<aop:aspect ref="loggingAspect">
? ? <aop:before method="beforeMethod" pointcut-ref="serviceOpearation"/>
? ? <aop:after method="afterMethod" pointcut-ref="serviceOpearation"/>
? ? <aop:after-returning method="afterReturning" pointcut-ref="serviceOpearation" returning="result"/>
? ? <aop:after-throwing method="afterThrowing" pointcut-ref="serviceOpearation" throwing="e"/>
</aop:aspect>
<!--<aop:advisor advice-ref=""/>-->
</aop:config>
測試結(jié)果:
在spring-context.xml中其實可以直接配置<aop:around method="aroundMethod" pointcut-ref="serviceOpearation"/>環(huán)繞通知渐行,等價于前面3個辦法的功能。
(2)基于注解的spring aop配置
LoggingAspect的配置改為如下:
package com.cyy.maven.core.Aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.util.Arrays;
/**
* @Author: Cyy
* @Description:
* @Date:Created in 16:00 2018/7/22
*/
@Slf4j
@Aspect
@Component
public class LoggingAspect {
@Pointcut("execution(* com.cyy.maven.core.service.impl.*.*(..))")
private void log(){}
@Before("log()")
public void beforeMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
? ? ? ? Object [] args = joinPoint.getArgs();
?????????log.info("The method={},begins with={}",methodName,Arrays.asList(args));
? ? }
@After("log()")
public void afterMethod(JoinPoint joinPoint){
String methodName = joinPoint.getSignature().getName();
? ? ? ? log.info("The method={},ends",methodName);
? ? }
@AfterReturning(pointcut ="log()",returning ="result")
public void afterReturning(JoinPoint joinPoint, Object result){
String methodName = joinPoint.getSignature().getName();
? ? ? log.info("The method={},ends with={}",methodName,result);
? ? }
@AfterThrowing(pointcut ="log()",throwing ="e")
public void afterThrowing(JoinPoint joinPoint, Exception e){
String methodName = joinPoint.getSignature().getName();
? ? ? ?log.error("The method={},occurs excetion:={}",methodName,e);
? ? }
//? ? @Around("log()")
? ? public ObjectaroundMethod(ProceedingJoinPoint pjd){
Object result =null;
? ? ? ? String methodName = pjd.getSignature().getName();
? ? ? ? try {
//前置通知
? ? ? ? ? ?log.info("The method={},begins with={}", methodName, Arrays.asList(pjd.getArgs()));
? ? ? ? ? ? //執(zhí)行目標方法
? ? ? ? ? ? result = pjd.proceed();
? ? ? ? ? ? //返回通知
? ? ? ? ? ?log.info("The method={},ends with={}",methodName ,result);
? ? ? ? }catch (Throwable e) {
//異常通知
? ? ? ? ? ? log.error("The method={}铸董,occurs exception:={}",methodName,e);
? ? ? ? ? ? throw new RuntimeException(e);
? ? ? ? }
//后置通知
? ? ? log.info("The method={},ends",methodName);
? ? ? ? return result;
? ? }
}
spring配置文件spring-context.xml的配置如下:
<!-- 配置自動掃描-->
<context:component-scan base-package="com.cyy.maven.core.Aspect"/>
<!--告訴JVM 我們用了aspectj的 annotation -->
<aop:aspectj-autoproxy/>
測試結(jié)果如圖:
在aroundMethod加上@Around("log()")祟印,注釋掉其他的注解,可以實現(xiàn)相同的功能粟害。
2.springboot的aop配置不用基于xml蕴忆,是完全基于注解的配置,和spring的注解配置很相似悲幅。
這里也直接用以前搭建的springboot框架來測試套鹅,碼云地址為https://gitee.com/cyy2csy/girl.git。
新建Aspect包汰具,下面新建HttpAspect織入類:
package com.cyy.Aspect;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.servlet4preview.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
@Slf4j
@Aspect
@Component
public class HttpAspect {
@Pointcut("execution(public * com.cyy.controller.GirlController.*(..))")
public void log(){}
@Before("log()")
public void doBefore(JoinPoint joinPoint){
ServletRequestAttributes attributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
? ? ? ? HttpServletRequest request= (HttpServletRequest) attributes.getRequest();
? ? ? ? log.info("執(zhí)行事務(wù)之前卓鹿。。留荔。");
? ? ? ? log.info("url={}",request.getRequestURI());
? ? ? ? log.info("method={}",request.getMethod());
? ? ? ? log.info("ip={}",request.getRemoteAddr());
? ? ? ? log.info("class-method={}",joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName());
? ? ? ? log.info("args={}",joinPoint.getArgs());
? ? }
@After("log()")
public void doAfter(){
log.info("執(zhí)行事務(wù)之后吟孙。。聚蝶。");
? ? }
@AfterReturning(returning ="object", pointcut ="log()")
public void doAfterReturning(Object object) {
log.info("response={}", object.toString());
? ? }
@AfterThrowing(pointcut ="log()",throwing ="e")
public void afterThrowing(JoinPoint joinPoint, Exception e){
String methodName = joinPoint.getSignature().getName();
? ? ? log.info("The method={}" + methodName +" occurs excetion:={}" + e);
? ? }
//? ? @Around("log()")
? ? public ObjectaroundMethod(ProceedingJoinPoint pjd){
Object object =null;
? ? ? ? String methodName = pjd.getSignature().getName();
? ? ? ? try {
//前置通知
? ? ? ? ? ? ServletRequestAttributes attributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
? ? ? ? ? ? HttpServletRequest request= (HttpServletRequest) attributes.getRequest();
? ? ? ? ? ? log.info("執(zhí)行事務(wù)之前杰妓。。碘勉。");
? ? ? ? ? ? log.info("url={}",request.getRequestURI());
? ? ? ? ? ? log.info("method={}",request.getMethod());
? ? ? ? ? ? log.info("ip={}",request.getRemoteAddr());
? ? ? ? ? ? log.info("class-method={}",pjd.getSignature().getDeclaringTypeName()+"."+pjd.getSignature().getName());
? ? ? ? ? ? log.info("args={}",pjd.getArgs());
? ? ? ? ? ? //執(zhí)行目標方法
? ? ? ? ? ? object = pjd.proceed();
? ? ? ? ? ? //返回通知
? ? ? ? ? ? log.info("response={}", object.toString());
? ? ? ? }catch (Throwable e) {
//異常通知
? ? ? ? ? log.info("The method={},occurs exception:={}",methodName,e);
? ? ? ? ? ? throw new RuntimeException(e);
? ? ? ? }
//后置通知
? ? ? ? log.info("執(zhí)行事務(wù)之后巷挥。。恰聘。");
? ? ? ? return object;
? ? }
}
測試結(jié)果:
同樣的句各,?將@Around("log()")加上吸占,將其他注解注釋掉,運行也是同樣的結(jié)果凿宾。