SpringAOP详解,使用SpringAop实现统一日志处理,异常处理

article/2025/9/14 7:29:12

阅读本文内容之前需要先了解java动态代理的实现。java动态代理实例

以下内容为本人原创>>>>>>>>>>>

Spring AOP的主要概念:

目标代码(或称目标方法、被代理类、被代理方法):原本的业务代码。
切点表达式(或称切面表达式):切点表达式过滤的规则,筛选范围,即哪些目标代码才需要切。
切点代码(或称切面代码连接点、代理方法):在原本的业务代码上包裹的切面逻辑。

Spring AOP注解

@Aspect

切面声明,标注在类、接口(包括注解类型)或枚举上,表示我这个类要切别人,或者我这个类是要代理别人的,要准备搞事了。
例子:

@Aspect//我要开始搞事了
public class MyAspect {@Around("@target(org.springframework.stereotype.Controller)")public void cutCode(ProceedingJoinPoint pjp){//...我真正搞事的代码}
}

@Pointcut

切点声明,可以理解为就是一个包含切点表达式的变量,为了避免@Before、@After等真实切点代码重复定义切点表达式。只是图个方便,不是必需品。
例子:

@Aspect//我要开始搞事了
public class MyAspect {@Pointcut("@target(org.springframework.stereotype.Controller)")public void myPoincut(){//这是只是喊口号,具体事务啥也不干}//@Around("@target(org.springframework.stereotype.Controller)")@Around(value="myPoincut()")//响应myPoincut方法的口号public void cutCode(ProceedingJoinPoint pjp){//...我真正搞事的代码}
}

@Before

前置通知,在目标方法(切入点)执行之前执行,接收JoinPoint参数。
value属性绑定通知的切入点表达式,可以关联切点声明(@Pointcut(切点表达式) myPoincut(){}@Before(value="myPoincut()") myBefore(JoinPoint jp){}),也可以直接设置切入点表达式(@Before("切点表达式"))。
注意:如果在此回调方法中抛出异常,则目标方法不会再执行,会继续执行后置通知异常通知
例子:

@Aspect//我要开始搞事了
public class MyAspect {@Pointcut("@target(org.springframework.stereotype.Controller)")public void myPoincut(){//这是只是喊口号,具体事务啥也不干}//@Before("@target(org.springframework.stereotype.Controller)")@Before(value="myPoincut()")//响应myPoincut方法的口号public void myBefore(JoinPoint jp){//...我真正搞事的代码,如果此处发生异常,那么目标方法不会再执行}
}

@After

后置通知,在目标方法执行之后执行,接收JoinPoint参数。
value属性绑定通知的切入点表达式,可以关联切点声明(@Pointcut(切点表达式) myPoincut(){}@After(value="myPoincut()") myAfter(JoinPoint jp){}),也可以直接设置切入点表达式(@After("切点表达式"))。
例子:

@Aspect//我要开始搞事了
public class MyAspect {@Pointcut("@target(org.springframework.stereotype.Controller)")public void myPoincut(){//这是只是喊口号,具体事务啥也不干}//@After("@target(org.springframework.stereotype.Controller)")@After(value="myPoincut()")//响应myPoincut方法的口号public void myAfter(JoinPoint jp){//...我真正搞事的代码}
}

@AfterReturning

返回通知,在目标方法返回结果之后,并且在@After切点执行之后执行。
该注解有四个属性pointcutvaluereturningargNames,pointcut和value属性都是绑定通知的切入点表达式,不过pointcut优先级高于value。returning属性则是使用了命名绑定模式(下文有介绍),定义返回值类型并接收返回值。argNames属性使用了命名绑定模式,定义参数类型、个数和顺序,和args(下文有介绍)效果一样,只是argNames优先级高于args。
注意:如果目标方法返回原生类型,则会报错,SpringAop不会自动给返回值装箱。
例子:

@Aspect//我要开始搞事了
public class MyAspect {@Pointcut("@target(org.springframework.stereotype.Controller)")public void myPoincut(){//这是只是喊口号,具体事务啥也不干}//@AfterReturning(returning = "result",value="@target(org.springframework.stereotype.Controller)")@AfterReturning(returning = "result",pointcut="myPoincut()")//响应myPoincut方法的口号public void myAfterReturning(JoinPoint jp,Object result){//result是目标方法的返回值,如果目标方法返回原生类型,则会报错,SpringAop不会自动给返回值装箱。//...我真正搞事的代码}
}

@AfterThrowing

异常通知,在目标方法抛出异常之后执行,意味着如果此通知被执行,则@AfterReturning不会被执行。
此注解有一个throwing属性,使用了命名绑定模式(下文有介绍),定义异常类型并接收异常对象。
注意:
1、如果目标方法自己try- catch了异常,而没有继续往外抛,则不会进入此通知。
2、@AfterThrowing虽然处理异常,但它不会阻止异常传播到上一级调用者,如果没有catch,则会导致jvm终止。

例子:

@Aspect//我要开始搞事了
public class MyAspect {@Pointcut("@target(org.springframework.stereotype.Controller)")public void myPoincut(){//这是只是喊口号,具体事务啥也不干}//@AfterThrowing(throwing = "e",value="@target(org.springframework.stereotype.Controller)")@AfterThrowing(throwing = "e",pointcut="myPoincut()")//响应myPoincut方法的口号public void myAfterThrowing(JoinPoint jp,Throwable e){//e是目标方法的真实发生异常后抛出的异常对象。//...我真正搞事的代码}
}

@Around

环绕通知:目标方法执行前后分别执行一些代码,接收ProceedingJoinPoint参数,可以控制目标方法是否继续执行。通常用于统计方法耗时,参数校验等操作。
环绕通知早于前置通知,晚于返回通知。
例子:

@Aspect//我要开始搞事了
public class MyAspect {@Pointcut("@target(org.springframework.stereotype.Controller)")public void myPoincut(){//这是只是喊口号,具体事务啥也不干}//@Around("@target(ctr)")//可以使用“命名绑定模式”定义切点表达式//public void cutCode(ProceedingJoinPoint pjp,org.springframework.stereotype.Controller ctr){//可以使用“命名绑定模式”定义切点表达式@Around(value="myPoincut()")//响应myPoincut方法的口号public Object cutCode(ProceedingJoinPoint pjp){//...我真正搞事的代码,前部分,这部分代码在@Before之前执行Object result = pjp.proceed();//调用目标方法//...我真正搞事的代码,后部分,这部分代码在@After之后执行return result;}
}

顺序总结

真实方法无异常:
@Around=>@Before=>真实方法=>@After=>@AfterReturning=>@Around
真实方法有异常:
@Around=>@Before=>真实方法=>@After=>@AfterThrowing=>@Around

以上内容为本人原创>>>>>>>>>>>

切点表达式

以下内容抄录自:最全 SpringAOP 切面表达式,内容我有细微改动和补充。

概述

切点表达式即PCD(pointcut designators ),SpringAOP的PCD是完全兼容AspectJ,一共有10种。
在这里插入图片描述

通配符

* 任意,不限制。
.. 0个或多个项,主要用于类名匹配式参数匹配式中,如果用于类名匹配式中,则表示匹配当前包及其子包,如果用于参数匹配式中,则表示匹配0个或多个参数。

运算符

切面表达式支持&&||! 这种逻辑操作,表示将多个表达式按照逻辑与、逻辑非、逻辑或的规则拼接起来。
&& 左右两个表达式同时满足(不是短路与)。
|| 左右两个表达式任意满足一个(不是短路或)。
! 非,取反。

execution(* com.xxx.spring.demo..*.login(java.lang.String,..))&&execution(* com.xxx.spring.demo2..*.test(java.lang.String,..))

命名绑定模式

命名绑定模式,就是在表达式中写上变量名,在方法上对变量名的类型进行限定。

@Around("within(per.aop.*) && args(str)")//在表达式中写上变量名str
public Object logAspect(ProceedingJoinPoint pjp, String str) {//在方法上对变量名str的类型进行限定,这里限定为String类型...
}

如上"within(per.aop.*) && args(str)",str必须是String类型或其子类,且方法入参只能有一个。
命名绑定模式只支持target、this、args三种PCD表达式。

execution

execution是最常用的PCD。它的匹配式模板如下展示:

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
execution(修饰符匹配式? 返回类型匹配式 类名匹配式? 方法名匹配式(参数匹配式) 异常匹配式?)

代码块中带?符号的匹配式都是可选的,对于execution PCD必不可少的只有三个:
返回值匹配值、方法名匹配式、参数匹配式

举例分析: execution(public * ServiceDemo.*(..)) 匹配public修饰符,返回值是*,即任意返回值类型都行,ServiceDemo是类名匹配式不一定要全路径,只要全局依可见性唯一就行,.*是方法名匹配式,匹配所有方法,…是参数匹配式,匹配任意数量、任意类型参数的方法。
栗子:

//匹配com.xyz.service及其子包下的任意方法
execution(* com.xyz.service..*.*(..))
//匹配任意名字为joke的方法,且其动态入参是是Object类型或该类的子类
execution(* joke(Object+)))
//匹配任意名字为joke的方法,该方法 一个入参为String(不可以为子类),后面可以有任意个入参且入参类型不限
execution(* joke(String,..))
//匹配指定包下find开头的方法
execution(* com..*.*Dao.find*(..))
//匹配com.baobaotao包下Waiter及其子类的所有方法
execution(* com.baobaotao.Waiter+.*(..))//以下示例摘录自:https://blog.csdn.net/u012156858/article/details/108429285
//匹配使用public修饰,返回值为任意类型,并且是com.xxx.spring.demo.LoginService类中名称为login的方法,方法包含两个参数,都是String类型。
execution(public * com.xxx.spring.demo.LoginService.login(java.lang.String,java.lang.String))
//对任何类的任何返回值的任何方法都有效
execution( * *.*(..))
//匹配使用public修饰,返回值为任意类型,并且是com.xxx.spring.demo包下任意类中名称为login的方法,方法包含两个参数,第一个参数类型是String 第二个参数任意
execution(public * com.xxx.spring.demo.*.login(java.lang.String,*))
//匹配使用public修饰,返回值为任意类型,并且是com.xxx.spring.demo包下任意类中名称为login的方法,方法包含多个参数,第一个参数类型是String 后面的参数任意
execution(public * com.xxx.spring.demo.*.login(java.lang.String,..))
//匹配使用public修饰,返回值为任意类型,并且是com.xxx.spring.demo包及其子包下任意类中名称为login的方法,方法包含多个参数,第一个参数类型是String 后面的参数任意
execution(public * com.xxx.spring.demo..*.login(java.lang.String,..))
//与上面示例完全一样 权限修饰符可写可不写 默认就是public
execution(* com.xxx.spring.demo..*.login(java.lang.String,..))
//以上示例摘录自:https://blog.csdn.net/u012156858/article/details/108429285

within

筛选出某包下的所有类,注意要带有*

@Pointcut("within(com.abc.service.*)")//com.abc.service包下的所有类,不包括子包下的类。
public void myPointcut1()
{
}
@Pointcut("within(com.xyz.service..*)")//com.xyz.service包下及其子包下的类
public void myPointcut2()
{
}

target

target作用于目标对象,即被代理对象(请先了解代理模式中代理对象和被代理对象)需要实现哪些接口,可以通过target来定义。常用于命名绑定模式,对被代理对象的类型进行过滤筛选。this和target的实际作用非常相似。

@Pointcut("target(mys)")//被代理类是MyService接口的实现
public void myPointcut1(MyService mys)
{
}
@Pointcut("target(mys)")//被代理类是MyServiceImpl类或者是MyServiceImpl的子类
public void myPointcut2(MyServiceImpl mys)
{
}

this

this作用于代理对象,即生成的代理对象(请先了解代理模式中代理对象和被代理对象)需要实现哪些接口,可以通过this来定义。常用于命名绑定模式,对被代理对象(我没写错,它和target的真实目的都是过滤被代理对象)的类型进行过滤筛选。this和target的实际作用非常相似。

如果目标类是基于接口实现的,则this()中可以填该接口的全路径名,目标类是基于CGLIB实现的,则this中可以填写目标类的全路径名。
使用@EnableAspectJAutoProxy(proxyTargetClass = true)可以强制使用CGLIB。否则默认首先使用jdk动态代理,jdk代理不了才会用CGLIB。

@Pointcut("this(mys)")//代理类是MyService接口的实现(也就是说明被代理类也必须这样,绕了一层后,其实最终目的还是为了筛选被代理类)
public void myPointcut1(MyService mys)
{
}
@Pointcut("this(mys)")//代理类是MyServiceImpl类或者是MyServiceImpl的子类(也就是说明被代理类也必须这样,绕了一层后,其实最终目的还是为了筛选被代理类)
public void myPointcut2(MyServiceImpl mys)
{
}

args

常用于对目标方法的参数匹配。一般不单独使用,而是配合其他PCD来使用。args可以使用命名绑定模式,如下举例:

@Aspect // 切面声明@Component // 注入IOC
@Slf4jclass 
AspectDemo {@Around("within(per.aop.*) && args(str)") // 在per.aop包下,且被代理方法的只有一个参数,参数类是String或者其子类@SneakyThrowspublicObject logAspect(ProceedingJoinPoint pjp, String str) { String signature = pjp.getSignature().toString();log.info("{} start,param={}", signature, pjp.getArgs());Object res = pjp.proceed();log.info("{} end", signature);return res;}
}

1.如果args中是参数名,则配合切面(advice)方法的使用来确定要匹配的方法参数类型。
2.如果args中是类型,例如@Around("within(per.aop.*) && args(String)"),则可以不必使用切面方法来确定类型,但此时也不能使用参数绑定了见下文了。
虽然args()支持+符号,但本身args()就支持子类通配。
和带参数匹配execution区别
举个例子: args(com.xgj.Waiter)等价于 execution(* *(com.xgj.Waiter+))。而且execution不能支持带参数的advice。

@annotation

@annotation属于方法名匹配式,指示筛选指定注解的方法作为被代理方法。
例子:

@Aspect//我要开始搞事了
public class MyAspect {@Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")//方法上有@RequestMapping注解的需要代理public void myPoincut(){}
}

@target

@target属于类名匹配式,指示筛选指定注解的类作为被代理类。
例子:

@Aspect//我要开始搞事了
public class MyAspect {@Pointcut("@target(org.springframework.stereotype.Controller)")//类上有@Controller注解的需要代理public void myPoincut(){}
}

@args

@args属于参数匹配式,指示筛选指定注解的参数类型作为被代理方法。是方法参数的类上有指定注解,不是方法参数上带注解。
例子:

@Aspect//我要开始搞事了
public class MyAspect {@Pointcut("@args(io.swagger.annotations.ApiModel)")//匹配1个参数,参数的类上运行时具有@ApiModel注解的需要被代理,不是方法参数有注解@ApiModelpublic void myPoincut1(){}@Pointcut("@args(io.swagger.annotations.ApiModel,..)")//匹配一个或多个参数,第一个参数的类上运行时具有@ApiModel注解的需要被代理public void myPoincut2(){}@Pointcut("@args(io.swagger.annotations.ApiModel,io.swagger.annotations.MyModel)")//匹配两个参数,第一个参数的类上运行时具有@ApiModel注解并且第二个参数的类上运行时具有@MyModel注解的需要被代理public void myPoincut3(){}
}

@within

非运行时类型的@target。

@target关注的是被调用的对象,@within关注的是调用的方法所在的类。

@target 和 @within 的不同点:

@target(注解A):判断被调用的目标对象中是否声明了注解A,如果有,会被拦截

@within(注解A): 判断被调用的方法所属的类中是否声明了注解A,如果有,会被拦截

bean

根据Spring Bean名称来匹配。支持*通配符。

bean(*Service) // 匹配所有Service结尾的Spring容器内对象

argNames

观察源码可以发现,所有的Advice注解都带有argNames字段,例如@Around:

@Around(value = "execution(* TestBean.paramArgs(..))  && args(decimal,str,..)&& target(bean)", argNames = "pjp,str,decimal,bean")@SneakyThrows // proceed会抛受检异常Object aroundArgs(ProceedingJoinPoint pjp,/*使用命名绑定模式*/ String str, BigDecimal decimal, Object bean) {// 在方法执行前做一些操作return  pjp.proceed();
}

argnames 必须要和args、target、this标签一起使用。虽然实际操作中可以不带,但官方建议所有带参数的都带,原因如下:

因此如果‘ argernames’属性没有指定,那么 Spring AOP 将查看类的调试信息,并尝试从局部变量表中确定参数名。只要使用调试信息(至少是‘-g: vars’)编译了类,就会出现此信息。使用这个标志编译的结果是:

(1)你的代码将会更容易被反向工程)

(2)类文件大小将会非常大(通常是无关紧要的)

(3)删除未使用的局部变量的优化将不会被编译器应用。

此外,如果编译的代码没有必要的调试信息,那么 Spring AOP 将尝试推断绑定变量与参数的配对。如果变量的绑定在可用信息下是不明确的,那么一个 AmbiguousBindingException 就会被抛出。如果上面的策略都失败了,那么就会抛出一个 IllegalArgumentException。
建议所有的advice注解里都带argNames,反正idea也会提醒。

以上内容抄录自:最全 SpringAOP 切面表达式,内容我有细微改动和补充。

实战

以下内容为本人原创>>>>>>>>>>>

使用SpringAOP实现全局日志处理

pom.xml

		<dependency><groupId>xxbs</groupId><artifactId>xxbs-util</artifactId><version>${xxbs.version}</version></dependency><dependency><groupId>xxbs</groupId><artifactId>xxbs-jwt</artifactId><version>${xxbs.version}</version></dependency><dependency><groupId>xxbs</groupId><artifactId>xxbs-bean</artifactId><version>${xxbs.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><scope>provided</scope></dependency>

application.properties

aopLog.enabled=true

AutoConfiguration.java

package tang.zhiyin.log.conf;import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import tang.zhiyin.log.aspect.AopLogAspect;@Configuration
@ConditionalOnProperty(name = "aopLog.enabled", havingValue = "true", matchIfMissing = false)
public class AutoConfiguration {@Beanpublic AopLogAspect sysLogAspect() {return new AopLogAspect();}
}

AopLogAspect.java

package tang.zhiyin.log.aspect;import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.web.multipart.MultipartFile;
import tang.zhiyin.base.bean.result.Result;
import tang.zhiyin.base.bean.result.ResultCodeEnum;
import tang.zhiyin.base.util.IpUtil;
import tang.zhiyin.base.util.SpringRequestUtil;
import tang.zhiyin.jwt.util.JwtUtil;import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;/*** AOP日志处理*/
@Slf4j
@Aspect
public class AopLogAspect {/*** 1、在tang.zhiyin.*.controller包下* 2、有RestController或者Controller注解的类* 3、有RequestMapping或者PostMapping或者GetMapping注解的方法*/private static final String execution = "execution(* tang.zhiyin.*.controller.*.*(..))" +"&&(@target(org.springframework.web.bind.annotation.RestController)" +"||@target(org.springframework.stereotype.Controller))" +"&&(@annotation(org.springframework.web.bind.annotation.RequestMapping)" +"||@annotation(org.springframework.web.bind.annotation.PostMapping)" +"||@annotation(org.springframework.web.bind.annotation.GetMapping))";@Around(value = execution)public Object cutCode(ProceedingJoinPoint pjp) {Map<String, String> logString = new LinkedHashMap<>(20);logString.put("用户ID", JwtUtil.getUserId() + "");logString.put("用户名", JwtUtil.getUserName());logString.put("Token", JwtUtil.getJwtToken());logString.put("URL", SpringRequestUtil.getRequest().getRequestURI());logString.put("HTTP方法", SpringRequestUtil.getRequest().getMethod());logString.put("客户IP", IpUtil.getIp(SpringRequestUtil.getRequest()));logString.put("服务器IP", IpUtil.getLocalIp());logString.put("线程", Thread.currentThread().getId() + "");logString.put("类", pjp.getTarget().getClass().getName());logString.put("方法", pjp.getSignature().getName());logString.put("接口参数", getParam(pjp.getArgs()));logString.put("BodyStream", getParams(SpringRequestUtil.getRequest()));logString.put("QueryString", SpringRequestUtil.getRequest().getQueryString());logString.put("User-Agent", SpringRequestUtil.getRequest().getHeader("User-Agent"));LocalDateTime startTime = LocalDateTime.now();Object result = null;try {result = pjp.proceed();//调用目标方法logString.put("返回值", JSONObject.toJSONString(result));} catch (Throwable e) {logString.put("异常信息", e.getMessage());logString.put("堆栈信息", StrUtil.sub(getStackTrace(e), 0, 65535));e.printStackTrace();
//            throw new RuntimeException(e);result = Result.build(ResultCodeEnum.SERVICE_ERROR.getCode(), "系统错误:" + e.getMessage());} finally {logString.put("用时", Duration.between(startTime, LocalDateTime.now()).toMillis() + "秒");if (logString.containsKey("异常信息")) {log.error(JSONObject.toJSONString(logString));} else {log.info(JSONObject.toJSONString(logString));}}return result;}public static String getStackTrace(Throwable throwable) {StringWriter sw = new StringWriter();try (PrintWriter pw = new PrintWriter(sw)) {throwable.printStackTrace(pw);return sw.toString();}}public static String getParams(HttpServletRequest request) {String param = "";try {BufferedReader br = new BufferedReader(new InputStreamReader(request.getInputStream(), "UTF-8"));//这流不能关闭String line = null;StringBuilder sb = new StringBuilder();while ((line = br.readLine()) != null) {sb.append(line);}param = sb.toString();} catch (Exception e) {e.printStackTrace();return "";}return param;}public static String getParam(Object[] args) {List<Object> params = new ArrayList<>(args.length);for (int i = 0; i < args.length; i++) {if (args[i] instanceof ServletRequest || args[i] instanceof ServletResponse) {continue;}if (args[i] instanceof FileItem) {FileItem file = (FileItem) args[i];Map<String, String> fileInfo = new LinkedHashMap<>();fileInfo.put("文件名", file.getName());fileInfo.put("文件大小", file.getSize() + "字节");params.add("文件流参数:" + JSONObject.toJSONString(fileInfo));} else if (args[i] instanceof MultipartFile) {MultipartFile file = (MultipartFile) args[i];Map<String, String> fileInfo = new LinkedHashMap<>();fileInfo.put("文件名", file.getOriginalFilename());fileInfo.put("文件大小", file.getSize() + "字节");params.add("文件流参数:" + JSONObject.toJSONString(fileInfo));} else {params.add(JSONObject.toJSONString(args[i]));}}return JSONObject.toJSONString(params);}
}

spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\tang.zhiyin.log.conf.AutoConfiguration

以上内容为本人原创>>>>>>>>>>>


http://chatgpt.dhexx.cn/article/b6xo4Xbm.shtml

相关文章

SpringAop学习(一)

Aop面向切面编程 AOP是Spring提供的关键特性之一。AOP即面向切面编程&#xff0c;是OOP编程的有效补充。使用AOP技术&#xff0c;可以将一些系统性相关的编程工作&#xff0c;独立提取出来&#xff0c;独立实现&#xff0c;然后通过切面切入进系统。从而避免了在业务逻辑的代码…

【Spring】SpringAOP切面类

切面类是什么 简单的来说&#xff0c;就是动态的在方法的指定位置添加指定的代码。 为什么需要切面类? 在软件开发的过程中&#xff0c;有很多业务&#xff0c;特别是在编写核心业务的时候&#xff0c;往往需要很多其他的辅助业务&#xff0c;比如说身份验证&#xff08;银…

SpringAOP超详解!!!!

文章目录 一、什么是SpringAOP二、SpringAOP的应用场景三、Aop在 Spring 中的作用四、AOP的实现方式1、方式一&#xff1a;使用原生Spring API接口2、方式二&#xff1a;自定义类方式三&#xff1a;注解 一、什么是SpringAOP SpringAOP的全称是&#xff08;Aspect Oriented Pr…

springAOP的原理解析

一、缘起 因为springAOP原理其实是使用jdk动态代理和cglib动态代理&#xff0c; 在深入了解springAOP的原理之前&#xff0c;我们需要先补充一点有关动态代理的相关的知识&#xff0c;然后我们对于springAOP的理解才会更透彻。所谓动态代理技术是程序在动态运行期间动态的增强某…

SpringAOP简单案例

简介 本文是一个老师在学校给学生上课的简单案例&#xff0c;介绍了AOP的五个通知的使用&#xff0c;以及通知的执行顺序。通过自定义注解来充当切入点&#xff0c;获取注解的类型分别对不同的老师做对应的业务处理。代码中的消息响应体&#xff08;Result&#xff09;大家可以…

springAOP面试题

1.什么是SpringAop? 一般称为面向切面编程&#xff0c;用于将那些与业务无关&#xff0c;但却对多个对象产生影响的公共行为和逻辑&#xff0c;抽取并封装为一个可重用的模块&#xff0c;这个模块被命名为“切面”&#xff08;Aspect&#xff09;&#xff0c;减少系统中的重复…

SpringAOP复习

作业1 目录 作业1一.单选题二.填空题三.判断题 一.单选题 1、以下不属于ProxyFactoryBean类中的常用可配置属性的是&#xff08;&#xff09;。 A、target B、proxyInterfaces C、targetClass D、interceptorNames 答案&#xff1a;C ProxyFactoryBean 是FactoryBean 接口的…

04、SpringAOP详解

1、Spring AOP简介 1、什么是AOP 1、定义阐述 AOP的全称是 Aspect Oriented Programming&#xff0c;是面向切面编程的技术&#xff0c;把一个个的横切关注点放到某个模块中去&#xff0c;称之为切面。那么每一个的切面都能影响业务的某一种功能&#xff0c;切面的目的就是功…

SpringAop之joinPoint讲解

一、学习背景 摸鱼的时候继续复刻demo&#xff0c;没错&#xff0c;同之前一篇文章&#xff0c;在写aop时又发现自己对aop只停留在面试阶段&#xff0c;甚至还不如&#xff0c;完全不会实践&#xff0c;所以在此记录复刻aop用到的的一些且自己已经遗忘的知识。 那么复刻的一个…

SpringAOP详细配置与使用

目录 SpringAOP简介 AOP概念 Spring AOP简单流程图 Spring AOP之Annotation 前置通知(Before advice) 返回后通知(After reurning advice) 抛出异常后通知(After throwing advice) 后置通知(After (finally) advice) 环绕通知(Around advice) 引入(Introduction) Sp…

SpringAOP的注解形式

铁子们&#xff0c;快扫码关注啦&#xff01;或 wx搜索&#xff1a;“聊5毛钱的java”&#xff0c;关注可领取博主的Java学习视频资料&#xff0c;保证都是干货 上一篇讲了配置文件形式的SpringAOP&#xff1a;Spring中的AOP以及切入点表达式和各种通知 本篇继续看一下注解形…

Spring AOP超详细解析

AOP - 面向切面编程&#xff08;Aspect Oriented Programming&#xff09; Spring早期版本的核心功能&#xff1a;管理对象生命周期与对象分配。 即Bean本身的管理创建&#xff0c;以及它整个生命周期里跟其他对象相互之间引用装配 为了更好的实现管理和装配&#xff0c;一个…

Spring学习:AOP概述

一、AOP概念 AOP是指面向切面编程&#xff0c;利用 AOP 可以对业务逻辑的各个部分进行隔离&#xff0c;从而使得业务逻辑各部分之间的耦合度降低&#xff0c;提高程序的可重用性&#xff0c;同时提高了开发的效率。 通俗描述&#xff1a;不通过修改源代码方式&#xff0c;在主干…

SpringAOP学习--SpringAOP简介及原理

前文对AOP做了介绍&#xff0c;实际项目中&#xff0c;一般不会直接上手手动实现aop&#xff0c;而是使用一些高级封装的aop实现&#xff0c;如SpringAOP。 Spring是一个广泛应用的框架&#xff0c;SpringAOP则是Spring提供的一个标准易用的aop框架&#xff0c;依托Spring的IOC…

图文详解Spring AOP,你学会了吗?

如果说 IOC 是 Spring 的核心&#xff0c;那么面向切面编程AOP就是 Spring 另外一个最为重要的核心&#xff0c;需要重点掌握mikechen 本篇主要会详解以下六点&#xff1a; 1.AOP的定义 2.AOP的作用 3.AOP的应用场景 4.Spring AOP的术语 AOP核心概念Spring AOP 通知分类S…

Spring AOP全面详解(超级详细)

如果说IOC 是 Spring 的核心&#xff0c;那么面向切面编程AOP就是 Spring 另外一个最为重要的核心mikechen AOP的定义 AOP &#xff08;Aspect Orient Programming&#xff09;,直译过来就是 面向切面编程,AOP 是一种编程思想&#xff0c;是面向对象编程&#xff08;OOP&…

mysql执行SQL脚本

方法一 【Mysql的bin目录】\mysql –u用户名 –p密码 –D数据库<【sql脚本文件路径全名】 示例&#xff1a; 如果mysql配了全局变量&#xff0c;就不需要到Mysql的bin目录下执行&#xff0c;可以在任何地方使用用户名、密码、指定数据库等参数值与参数名不需要隔空格 不…

SpringBoot 实现SQL脚本自动执行

SpringBoot 实现配置SQL脚本自动执行 一. 背景 我们可能遇到过这种情况: 在公网开发时, 新增数据表非常容易, 直接登录到对应服务器的mysql / 使用Navicat访问mysql服务器. 然后去执行sql语句或脚本即可在内网开发时, 由于都在一个网段, 所以操作也比较方便但是在公网开发, 部…

flink-sql-client提交sql脚本文件

标题: flink-sql-client提交sql脚本文件 日期: 2021-10-22 22:11:34 标签: [flink,sql-client] 分类: flink 我们知道&#xff0c;sql-client.sh可以提供给我们一个sql交互界面&#xff0c;让我们没执行一个sql&#xff0c;就可以看到执行结果&#xff0c;也可以交互式查询表的…

如何在mysql中执行sql脚本文件

一、sql脚本文件 简介 xxxx.sql这种文件被称为sql脚本文件。sql脚本文件中编写了大量的sql语句。我们执行sql脚本文件的时候&#xff0c;该文件中所有的sql语句会全部执行&#xff01;批量的执行SQL语句&#xff0c;可以使用sql脚本文件。 上面这个vip.sql就是sql脚本文件&am…