https://juejin.cn/post/6844903720203862023
https://blog.51cto.com/u_15155081/2720729
package com.yangxin.core.transaction;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class TransactionDemo2 {
@Pointcut(value="execution(* com.yangxin.core.service.*.*.*(..))")
public void point(){
}
@Before(value="point()")
public void before(){
System.out.println("transaction begin");
}
@AfterReturning(value = "point()")
public void after(){
System.out.println("transaction commit");
}
@Around("point()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("transaction begin");
joinPoint.proceed();
System.out.println("transaction commit");
}
}
切面(Aspect):是一个类,里面定义了通知与切点。
切点(PointCut):表达式。就是告诉程序要在执行哪些核心业务的时候,执行非核心的业务。
通知(advice):五种通知方式:
@Before:前置通知,在调用目标方法之前执行通知定义的任务
@After:后置通知,在目标方法执行结束后,无论执行结果如何都执行通知定义的任务
@After-returning:后置通知,在目标方法执行结束后,如果执行成功,则执行通知定义的任务
@After-throwing:异常通知,如果目标方法执行过程中抛出异常,则执行通知定义的任务
@Around:环绕通知,在目标方法执行前和执行后,都需要执行通知定义的任务。
连接点(Join point)
连接点是在应用执行过程中能够插入切面的一个点。
<aop:aspectj-autoproxy/> 使用这个在springaop中开启aspectJ注解
、
1.通过 @EnableAspectJAutoProxy解或者 XML 配置(
<aop:aspect-autoproxy>)可以激活 AOP 模块,底层会注册一个 AbstractAutoProxyCreator 类型的 Bean 完成 AOP 自动代理
2.Spring AOP 中的自动代理主要由 AbstractAutoProxyCreator 这个 Bean 进行创建,因为它实现了几种 BeanPostProcessor,例如在 Bean 加载过程中,初始化后会调用 AbstractAutoProxyCreator 的方法进行处理,返回一个代理对象
这个地方存疑?:初始化的时候会引入其他的bean,解决bean的循环依赖的时候,三级缓存是可以生成代理对象,这个地方我觉得应该是没有循环依赖的在beanpostprocess.afterInitialization
之后实现,有依赖场景在初始化的时候进行生成了
解决上面的疑问
Spring AOP 自动代理的实现主要由 AbstractAutoProxyCreator 完成,它实现了
BeanPostProcessor、SmartInstantiationAwareBeanPostProcessor 和InstantiationAwareBeanPostProcessor
三个接口,那么这个类就是 Spring AOP 的入口,在这里将 Advice 织入我们的 Bean 中,创建代理对象。
三级缓存走的类依赖
总结创建代理对象
通过1.getAdvicesAndAdvisorsForBean(),找出合适的advisor对象
2.通过createProxy(),根据找到的advisor创建一个代理对象,jdk动态代理或者CGlib动态代理
(这个createProxy就是在warpIfNessary中的方法)
设计模式使用:
super: 代理模式
1.策略模式:
createAopProxy
2.模板模式
子类实现具体的方法,父类实现模板方法
3.责任链模式:
具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下家。由于具体处理者持有对下家的引用
4.适配器:
将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
实现:
1.全部通过xml实现:
切面实现(log日志)
package com.lagou.edu.utils;
/**
* @author 应癫
*/
public class LogUtils {
/**
* 业务逻辑开始之前执行
*/
public void beforeMethod(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
System.out.println(arg);
}
System.out.println("业务逻辑开始执行之前执行.......");
}
/**
* 业务逻辑结束时执行(无论异常与否)
*/
public void afterMethod() {
System.out.println("业务逻辑结束时执行,无论异常与否都执行.......");
}
/**
* 异常时时执行
*/
public void exceptionMethod() {
System.out.println("异常时执行.......");
}
/**
* 业务逻辑正常时执行
*/
public void successMethod(Object retVal) {
System.out.println("业务逻辑正常时执行.......");
}
}
public Object arroundMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕通知中的beforemethod....");
Object result = null;
try{
// 控制原有业务逻辑是否执行
// result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
}catch(Exception e) {
System.out.println("环绕通知中的exceptionmethod....");
}finally {
System.out.println("环绕通知中的after method....");
}
return result;
}
1.设置bean
2.设置aop:config
指定切点<AOP:POINT> 指定通知 <AOP:BEFORE/AFTER/AROUND>
<!--进行aop相关的xml配置,配置aop的过程其实就是把aop相关术语落地-->
<!--横切逻辑bean-->
<bean id="logUtils" class="com.lagou.edu.utils.LogUtils"></bean>
<!--使用config标签表明开始aop配置,在内部配置切面aspect-->
<!--aspect = 切入点(锁定方法) + 方位点(锁定方法中的特殊时机)+ 横切逻辑 -->
<aop:config>
<aop:aspect id="logAspect" ref="logUtils">
<!--切入点锁定我们感兴趣的方法,使用aspectj语法表达式-->
<!--..参数中的两个点表示可以有参数,也可以没有参数,有的话也可以是任意类型,参数中的 *表示参数可以是任意类型,但必须有参数。 -->
<!--包名中的..两个点表示中间可以是任意层-->
<!--<aop:pointcut id="pt1" expression="execution(* *..*.*(..))"/>-->
<aop:pointcut id="pt1" expression="execution(public void com.lagou.edu.service.impl.TransferServiceImpl.transfer(java.lang.String,java.lang.String,int))"/>
<!-- <aop:pointcut id="pt1" expression="execution(* com.lagou.edu.service.impl.TransferServiceImpl.*(..))"/>
-->
<!--方位信息,pointcut-ref关联切入点-->
<!--aop:before前置通知/增强-->
<aop:before method="beforeMethod" pointcut-ref="pt1"/>
<!--aop:after,最终通知,无论如何都执行-->
<!--aop:after-returnning,正常执行通知,retValue是接受方法的返回值的-->
<aop:after-returning method="successMethod" returning="retValue"/>
<!--aop:after-throwing,异常通知-->
<aop:around method="arroundMethod" pointcut-ref="pt1"/>
</aop:aspect>
</aop:config>-->
二:通过纯注解方式实现:
package com.lagou.edu.utils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
/**
* @author 应癫
*/
@Component
@Aspect
public class LogUtils {
@Pointcut("execution(* com.lagou.edu.service.impl.TransferServiceImpl.*(..))")
public void pt1(){
}
/**
* 业务逻辑开始之前执行
*/
@Before("pt1()")
public void beforeMethod(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
System.out.println(arg);
}
System.out.println("业务逻辑开始执行之前执行.......");
}
/**
* 业务逻辑结束时执行(无论异常与否)
*/
@After("pt1()")
public void afterMethod() {
System.out.println("业务逻辑结束时执行,无论异常与否都执行.......");
}
/**
* 异常时时执行
*/
@AfterThrowing("pt1()")
public void exceptionMethod() {
System.out.println("异常时执行.......");
}
/**
* 业务逻辑正常时执行
*/
@AfterReturning(value = "pt1()",returning = "retVal")
public void successMethod(Object retVal) {
System.out.println("业务逻辑正常时执行.......");
}
/**
* 环绕通知
*
*/
/*@Around("pt1()")*/
public Object arroundMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕通知中的beforemethod....");
Object result = null;
try{
// 控制原有业务逻辑是否执行
// result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
}catch(Exception e) {
System.out.println("环绕通知中的exceptionmethod....");
}finally {
System.out.println("环绕通知中的after method....");
}
return result;
}
}
只需要在配置文件中增加一个配置项即可:
<!--开启aop注解驱动
proxy-target-class:true强制使用cglib
-->
<aop:aspectj-autoproxy/>
甚至我们可以不使用xml文件
使用纯注解
在启动类上加上
@EnableAspectJAutoProxy