浅谈 Spring AOP 思想

文章介绍了SpringAOP的概念,包括普通代理类、JDK动态代理和Cglib动态代理的使用,强调了AOP无侵入的优点。同时,讨论了AOP的术语,如通知类型(Before、After等)和切入点表达式。此外,还探讨了Spring事务管理的@Transaction注解及其rollback和propagation属性。
摘要由CSDN通过智能技术生成

AOP 切面编程

AOP 底层是基于动态代理思想实现的 可以把核心业务业务逻辑看作是一个圆增强的业务逻辑也看成是一个圆,核心业务逻辑在增强的业务逻辑的中央,这样就形成了一个同心圆(切面), 这种编程思想的好处是 无侵入 即 不会对源码进行修改。以一个为核心业务逻辑增加日志的例子来逐步引出动态代理和AOP面向切面编程思想。

普通代理类

最原始的方式是利用代理类的方式为核心业务逻辑增添打印日志的功能,这就要求被代理类和增强类要同时实现一个接口来保证方法的一致性,但是还需要为每一个代理类都创建一个对象,当增强的方法都相同时就造成了代码的重复编写,造成了开发效率的降低。下面这种是修改源码的方式。
在这里插入图片描述
在这里插入图片描述

目前代码存在两个问题
代码耦合性高:业务代码和日志代码耦合在了一起
代码复用性低:日志代码在每个方法都要书写一遍

在这里插入图片描述

JDK动态代理

为了解决基本代理方式的不足,产生了JDK动态代理的方式,但是这样的方式还有一个不足,就是只能对接口的实现类进行代理,在此背景下,Cglib动态代理又出现了,Cglib动态代理可以为类动态创建代理类。
PS: 在创建代理对象时 jdk的速度要高于cglib
所以选择的时候:
当被代理类有接口的时候,使用jdk动态代理
当被代理类没有接口的时候,使用cglib动态代理

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class DeptServiceTest {

    @Autowired
    private DeptService deptService;

    @Autowired
    private Logger logger;

    @Test
    public void test1() {

        InvocationHandler myHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                logger.m1();

                try {

                    method.invoke(deptService,args);

                } catch (Exception e) {

                    logger.m3();
                }
                logger.m2();

                return null;
            }
        };


      DeptService deptServiceproxy = (DeptService) Proxy.newProxyInstance(
                deptService.getClass().getClassLoader(),
                new Class[]{DeptService.class},
               myHandler
        );


        deptServiceproxy.save(null);
        deptServiceproxy.findAll();
        deptServiceproxy.findById(null);
    }

}

在这里插入图片描述

Cglib动态代理

在这里插入图片描述

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class DeptServiceTest {


    @Autowired
    private DeptServiceImpl deptService;

    @Autowired
    private Logger logger;

    @Test
    public void test01() {

        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                logger.m1();

                try {
                    method.invoke(deptService, args);
                } catch (Exception e) {
                    logger.m3();
                }
                logger.m2();
                return null;
            }
        };


        DeptServiceImpl deptServiceProxy = (DeptServiceImpl) Enhancer.create(DeptServiceImpl.class, invocationHandler);
        //注意: Enhancer有个硬伤,就是无法对已经封装过的targetclass,再继续封装多一次,无法实现多个interceptor的链式调用。


        deptServiceProxy.findAll();
        System.out.println("=============================");
        deptServiceProxy.save(null);
        System.out.println("=============================");
        deptServiceProxy.findById(null);
    }
}

首先通过enhancer创建代理类,再创建代理类的实例对象
在这里插入图片描述

AOP

切面类要使用两个注解 @Component 和 @Aspect 声明该类为一个切面类,并且将该切面类加入到Spring容器中,在切面类中可以定义切点 @ PointCut()和通知 (5种),下面会展开详细叙述
在这里插入图片描述

AOP术语

在这里插入图片描述

AOP切面编程的优势

在这里插入图片描述

Advice通知类型(5种)

@Before:前置通知,此注解标注的通知方法在目标方法前被执行
@AfterReturning: 返回后通知,此注解标注的通知方法在目标方法后被执行,有异常不会执行
@AfterThrowing: 异常后通知,此注解标注的通知方法发生异常后执行
@After:后置通知,此注解标注的通知方法在目标方法后被执行,无论是否有异常都会执行

@Around

@Around环绕通知需要自己调用 ProceedingJoinPoint.proceed() 来让原始方法执行,其他通知不需要考虑目标方法执行
@Around环绕通知方法的返回值,必须指定为Object,来接收原始方法的返回结果  Object result = pjp.proceed();

通知的执行顺序 @Order

不同切面类中,默认按照切面类的全类名字母排序:
目标方法前的通知方法:字母排名靠前的先执行
目标方法后的通知方法:字母排名靠前的后执行
相当于一个嵌套的效果一样,类比Filter中的过滤器链的执行顺序,也是按照全类名字母靠前的先执行

切入点表达式

切入点表达式:描述切入点方法@PointCut()的一种表达式
作用:主要用来决定项目中的哪些方法需要加入通知
常见形式:
在这里插入图片描述

表达式@execution

execution(……):根据方法的签名来匹配,常与通配符(* 和 …)搭配使用 ,…用在参数表示0或n个参数 *模糊匹配

使用切入点表达式 需要指定 权限修饰符 返回值类型 方法名的全名(带全类名) 参数 ,因此excution常与通配符搭配用来定义方法名有规律的切入点
在这里插入图片描述

注解@annotation

@annotation(……) :根据注解匹配,使用注解方式,需要自定义注解,常用来定义方法名无规律的切入点pointcut,自定义注解,如下所示:@annotation(注解全类名)

在这里插入图片描述

在切点配置自定义注解,用于识别对那些方法进行增强
在这里插入图片描述
配置切点注解
在这里插入图片描述

Spring事务管理

在Spring容器中使用事务时还需要在Spring配置类中配置@EnableTransactionMangement注解和@Bean配置事务管理器
在这里插入图片描述

@Transactional 及 @Transactional 的两个属性

位置:业务(service)层的方法上、类上、接口上
作用:将当前方法交给spring进行事务管理,方法执行前,开启事务;成功执行完毕,提交事务;出现异常,回滚事务

注解用在方法上,表示为方法开启事务,用在类上表示为类中所有方法开启事务,用在接口上表示为接口的所有实现类开启事务

@Transactional 的 rollback 回滚 属性

默认情况下,只有出现 RuntimeException 才回滚异常,rollbackFor属性用于控制让非运行时异常也回滚。
因此,需要为 @Transactional的rollback属性指定异常类类型让其对所有异常都进行回滚
在这里插入图片描述

@Transactional 的 propagation 传播行为 属性

事务传播行为:指的就是当一个事务方法被另一个事务方法调用时,这个事务方法应该如何进行事务控制。通俗点说就是:一个有事务注解修饰的方法在被另一个开启了事务的方法调用时,该方法的事务怎么办的问题。默认值是required

在这里插入图片描述
2中比较常用的是 required (默认) 有事务就加入,无事务就创建新的 和 requires_new 事务不影响
在这里插入图片描述

AOP相关注解总结(十一)

配置切面相关注解

@Component

@Aspect

@PointCut

@annotation

通知相关注解

@Before
@AfterReturning
@AfterThrowing
@After
@Around
@Oredr

事务相关注解

@EnableTransactionMangement

@Transactional

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

PY_XAT_SFZL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值