【spring6】面向切面编程AOP

     AOP是对OOP(面向对象编程)的补充延伸,底层使用的就是动态代理(JDK动态代理 + CGLIB动态代理技术)来实现的。将与核心业务无关的代码独立的抽取出来,形成一个独立的组件,然后以横向交叉的方式应用到业务流程当中的过程被称为AOP。

     应用:一个系统会有交叉业务,例如:日志、事务管理、安全等。交叉业务代码在多个业务流程中反复出现,这个交叉业务代码没有得到复用,并且修改这些交叉业务代码的话,需要修改多处。程序员无法专注核心业务代码的编写,在编写核心业务代码的同时还需要处理这些交叉业务。使用AOP可以解决这些问题。

     优点:1)代码复用性增强;2)易于维护;3)使开发者更关注业务逻辑

1.AOP的七大术语

     1)连接点 (Joinpoint):在程序的整个执行流程中,可以织入切面的位置。方法的执行前后,异常抛出之后等位置

     2)切点(Pointcut):在程序执行流程中,真正织入切面的方法,选定的连接点

     3)通知(Advice):具体你要织入的代码,包括:前置通知、后置通知、环绕通知、异常通知、最终通知

     4)切面 (Aspec):切点 + 通知

     5)织入(Weaving):把通知应用到目标对象上的过程

     6)代理对象(Proxy):一个目标对象被织入通知后产生的新对象

     7)目标对象(Target):被织入通知的对象

2.切点表达式

 execution([访问控制权限修饰符] 返回值类型 [全限定类名]方法名(形式参数列表) [异常])

     访问控制权限修饰符:可选项;没写,就是4个权限都包括;public就表示只包括公开的方法。

     返回值类型:必填项;* 表示返回值类型任意。

     全限定类名:可选项;两个点“..”代表当前包以及子包下的所有类;省略时表示所有的类。

     方法名:必填项;*表示所有方法;set*表示所有的set方法。

     形式参数列表:必填项;() 表示没有参数的方法;(..) 参数类型和个数随意的方法;(*) 只有一个参数的方法;(*, String) 第一个参数类型随意,第二个参数是String的。

     异常:可选项;省略时表示任意异常类型。

execution(* com.powernode.service..*(..))       //service包下所有的类的所有的方法

3.使用AOP

     包括3种方式:

        1)Spring框架结合AspectJ框架实现的AOP,基于注解方式

        2)Spring框架结合AspectJ框架实现的AOP,基于XML方式

        3)Spring框架自己实现的AOP,基于XML配置方式

     依赖:

<!--spring aop依赖-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aop</artifactId>
  <version>6.0.0-M2</version>
</dependency>
<!--spring aspects依赖-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>6.0.0-M2</version>
</dependency>

      例:

// 目标类
@Component//纳入Bean管理
public class Service {
    // 目标方法
    public void do(){
        
    }
}

// 切面类
@Aspect
@Component//纳入Bean管理
public class MyAspect {
 // 切点表达式,前置通知
    @Before("execution(* spring6.service.Service.*(..))")
 //需要增强的代码(通知)
    public void advice(){
        System.out.println("订单已生成!");
    }
}

    <!--开启组件扫描-->
    <context:component-scan base-package="spring6.service"/>
    <!--开启自动代理-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>

     注意:

        <aop:aspectj-autoproxy proxy-target-class="true"/> 开启自动代理之后,凡事带有@Aspect注解的bean都会生成代理对象。

        proxy-target-class="true" 表示采用cglib动态代理。

        proxy-target-class="false" 表示采用jdk动态代理。默认值是false。即使写成false,当没有接口的时候,也会自动选择cglib生成代理类。

     通知类型:

        1)前置通知:@Before 目标方法执行之前的通知

        2)后置通知:@AfterReturning 目标方法执行之后的通知

        3)环绕通知:@Around 目标方法之前添加通知,同时目标方法执行之后添加通知。

        4)异常通知:@AfterThrowing 发生异常之后执行的通知

        5)最终通知:@After 放在finally语句块中的通知

// 切面类
@Component
@Aspect
public class MyAspect {

    @Around("execution(* spring6.service.OrderService.*(..))")
    public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕通知开始");
        // 执行目标方法。
        proceedingJoinPoint.proceed();
        System.out.println("环绕通知结束");
    }

    @Before("execution(* spring6.service.OrderService.*(..))")
    public void beforeAdvice(){
        System.out.println("前置通知");
    }

    @AfterReturning("execution(* spring6.service.OrderService.*(..))")
    public void afterReturningAdvice(){
        System.out.println("后置通知");
    }

    @AfterThrowing("execution(* spring6.service.OrderService.*(..))")
    public void afterThrowingAdvice(){
        System.out.println("异常通知");
    }

    @After("execution(* spring6.service.OrderService.*(..))")
    public void afterAdvice(){
        System.out.println("最终通知");
    }

}

     当发生异常时:

     切面的先后顺序:可以使用@Order注解来标识切面类,为@Order注解的value指定一个整数型的数字,数字越小,优先级越高

     优化使用切点表达式:

public class MyAspect {
    
    @Pointcut("execution(* spring6.service.OrderService.*(..))")
    //方法随意,只为了表示@Pointcut位置
    public void pointcut(){}

    @Before("pointcut()")
    public void beforeAdvice(){
        System.out.println("前置通知");
    }
}

     全注解式开发AOP:

@Configuration
@ComponentScan("spring6.service")
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class SpringConfiguration {
}

     基于XML配置方式的AOP:

<!--切面类-->
<bean id="timerAspect" class="spring6.service.TimerAspect"/>

    <!--aop配置-->
    <aop:config>
        <!--切点表达式-->
        <aop:pointcut id="p" expression="execution(* spring6.service.VipService.*(..))"/>
        <!--切面-->
        <aop:aspect ref="timerAspect">
            <!--切面=通知 + 切点-->
            <aop:around method="time" pointcut-ref="p"/>
        </aop:aspect>
    </aop:config>

4.实际案例

        事务:

@Aspect
@Component
// 事务切面类
public class TransactionAspect {
    
    @Around("execution(* spring6.biz..*(..))")
    public void aroundAdvice(ProceedingJoinPoint proceedingJoinPoint){
        try {
            System.out.println("开启事务");
            // 执行目标
            proceedingJoinPoint.proceed();
            System.out.println("提交事务");
        } catch (Throwable e) {
            System.out.println("回滚事务");
        }
    }
}

        日志:

@Component
@Aspect
public class SecurityAspect {

    @Pointcut("execution(* spring6.service..save*(..))")
    public void savePointcut(){}

    @Pointcut("execution(* spring6.service..delete*(..))")
    public void deletePointcut(){}

    @Pointcut("execution(* spring6.service..modify*(..))")
    public void modifyPointcut(){}

    @Before("savePointcut() || deletePointcut() || modifyPointcut()")
    public void beforeAdivce(JoinPoint joinpoint){
        System.out.println("XXX操作员正在操作"+joinpoint.getSignature().getName()+"方法");
    }
}
  • 43
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值