Spring-Aop

Spring-Aop

AOP:面向切面编程,AOP对OOP补枪;

  • OOP:宏观层面的思想,对项目的整体架构
  • AOP:站在方法的层面,不改变原来的代码基础,动态增强原来的方法

OOP:在编程的过程中会将重复的功能代码剥离出来,单独写一个方法,或者类,然后需要使用的时候在调用。提高了代码复用率,提升编程体验,但是还是有一定的耦合与不便。

AOP:站在OOP巨人的肩膀上,在不需要修改源码的基础上,给程序动态同意添加额外功能的一种技术。

AOP的优点
  1. 在不改变核心代码的前提下,动态的添加额外的功能
  2. 业务逻辑与非业务逻辑的解耦
  3. 解耦后可专心的实现某个功能
  4. 业务与非业务功能性能灵活组装(通过配置文件,或者注解)
  • AOP面向切面编程:我们实现业务层的时候,业务层除了本身的逻辑代码,还需要其他的权限验证(先验证使用功能的权限在考虑是否放行),事物控制(逻辑代码中涉及到的所有sql语句,必须由事物控制,保证数据的安全性),日志记录(每个行为都应该有日记的记录)等等这些功能。
  • 并且这些功能都是每个功能最基本的需求,也就是需要剥离出来,封装成代码,但是传统的OOP会带来一个问题,逻辑代码与这些功能还是有直接耦合,需要修改,或者动态的选择性调用这些涉及到修改源代码,这是我们所不能接受的。
  • 因此AOP跨出了伟大的一步,将逻辑代码这一块看做一个功能,一个切面,其他额外的功能依附在切面上,不对该逻辑代码进行改变,降低了入侵性,完成了解耦。
  • 将业务层逻辑代码比作是一面墙,spring中的配置文件或者注解相当于一个可以占在墙上的挂钩,而像权限验证、事物控制、日志记录相当于不同衣服,所以这面墙上就有三件衣服,承担不同的功能,想要不同的衣服,那就添加配置,在添加功能,如果不需要了将衣服取下来,粘钩拿掉,这面墙还是之前的那面墙没有什么变化。

AOP基于XML配置文件方法

  1. 导入Aop的相关依赖:为了开发的便捷使用的是基于Spring的aspectj

     <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-context</artifactId>
         <version>${spring.version}</version>
     </dependency>
    <!--spring-aop在spring-context已经传递-->
    <!--aspectJ的依赖: 会在spring-aspects传递-->
    <!-- <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.9.7</version>
            </dependency>-->
    <!--spring整合aspectJ的依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
        <version>${spring.version}</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.36</version>
    </dependency>
    
  2. 编写通知类

    • before:前置增强
    • afterReturning:后置增强
    • afterThrowing:异常增强
    • after:最终增强
    • aroud:环绕增强(包括前面四种)
  3. 在Spring配置文件中的配置

    • 把通知类交给spring管理

      @Component("bizLogger")
      public class BizLogger {
      
    • 在spring配置文件中配置Aop的相关配置

      <!--把增强类(通知类)与目标类进行织入 -->
              <aop:config>
                  <!--切入点: 对那些类那些方法进行增强
                    属性:
                      id: 唯一标志符
                      public void com.fs.aop.service.impl.UserServiceImpl.addUser(参数列表) throws Exception
                       public void com.fs.aop.service.impl.*.*(..) throws Exception
                      expression:表达式 切入点表达式
                        语法: execution(修饰符? 返回值 方法名(参数) 异常?)
                        语法: ?: 0次或者1次
                        通配符:
                            *: 任意
                           ..:参数列表中使用, 任意多个任意类型的参数
                  -->
                    <aop:pointcut id="pointcut1" expression="execution(* com.fs.aop.service..*.*(..))"/>
                    <!--织入
                       通知类方法与目标方法进行组装
                       5类通知:
                        前置通知
                    -->
                   <!--通知类
                     ref: 通知类的bean的id
                   -->
                  <!--基于AspectJ的配置-->
                   <aop:aspect ref="bizLogger">
                        <!--前置通知
                          method: 通知类的那个方法作为前置通知, 方法名
                           pointcut-ref: 切入点的id
                        -->
                       <!-- <aop:before method="before" pointcut-ref="pointcut1"></aop:before>-->
      
                       <!--后置通知: 目标方法正常执行之后,返回结果 的增强
                          returning: 把目标方法的返回值 赋值给afterReturning那个参数, 参数名
                       -->
                      <!-- <aop:after-returning returning="result" method="afterReturning" pointcut-ref="pointcut1"></aop:after-returning>-->
      
                       <!--最终增强-->
                       <!--<aop:after method="after" pointcut-ref="pointcut1"></aop:after>-->
                       <!--异常增强
                         throwing: 把目标方法抛出异常对象赋值给增强方法那个参数接收  参数名
                       -->
                       <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut1" throwing="e"></aop:after-throwing>
                        <!--环绕增强-->
                       <aop:around method="aroundLogger" pointcut-ref="pointcut1"></aop:around>
      
                   </aop:aspect>
      
              </aop:config>	
      

AOP基于注解的方式

  1. 在通知类上添加一个注解,表示它是通知类(@Aspect)

  2. 在增强的方法上添加对应的增强类型注解

      package com.fs.aop.log;
    
      import java.sql.SQLException;
      import java.util.Arrays;
    
      import lombok.extern.slf4j.Slf4j;
      import org.apache.log4j.Logger;
      import org.aspectj.lang.JoinPoint;
      import org.aspectj.lang.ProceedingJoinPoint;
      import org.aspectj.lang.annotation.*;
      import org.springframework.stereotype.Component;
    
      /**
       * 日志增强类
       */
      @Slf4j
      @Component("bizLogger")
      @Aspect  //表示该类是一个通知类
      public class BizLogger {
      	/**
      	 * 前置增强
      	 *   JoinPoint: 连接点 addUser()方法对象
      	 *    UserServiceImpl的addUser(User user)
      	 *   getTarget(): 目标方法的目标对象 UserServiceImpl对象
      	 *   getSignature(): 目标方法 addUser()
      	 *   getArgs(): 目标方法的参数的值
      	 * @param jp
      	 */
      	@Before("execution(* com.fs.aop.service..*.*(..))")
      	public void before(JoinPoint jp){
      		log.info("调用"+jp.getTarget()+"的"+jp.getSignature().getName()
      				+"方法,传递的参数:"+Arrays.toString(jp.getArgs()));
      	}
    
      	/**
      	 * 后置增强
      	 * @param jp
      	 * @param result  返回值
      	 */
      	@AfterReturning(value = "execution(* com.fs.aop.service..*.*(..))",returning = "result")
      	public void afterReturning(JoinPoint jp,Object result){
      		log.info("调用"+jp.getTarget()+"的"+jp.getSignature().getName()
      				+"方法,方法的返回值:"+result);
      	}
    
      	/**
      	 * 异常增强
      	 * @param jp
      	 * @param e 增强的异常类型
      	 *          SQLException: 这个异常增强只对目标方法抛出异常对象类型SQLException以及子类才执行
      	 */
      	@AfterThrowing(value = "execution(* com.fs.aop.service..*.*(..))",throwing = "e")
      	public void afterThrowing(JoinPoint jp,Exception e){
      		log.error("调用"+jp.getTarget()+"的"+jp.getSignature().getName()
      				+"方法发生异常"+e);
      	}
    
      	/**
      	 * 最终增强
      	 * @param jp
      	 */
      	@After("execution(* com.fs.aop.service..*.*(..))")
      	public void after(JoinPoint jp){
      		log.info(jp.getSignature().getName()+"方法执行结束");
      	}
    
      	/**
      	 * 环绕增强
      	 * @param jp
      	 *   ProceedingJoinPoint是JoinPoint子类
      	 *     proceed()方法: 调用这个方法, 调用目标方法, 没有调用, 目标方法都不执行
      	 * @throws Throwable
      	 */
      	@Around("execution(* com.fs.aop.service..*.*(..))")
      	public Object aroundLogger(ProceedingJoinPoint jp) throws Throwable{
      		log.info(jp.getSignature().getName()+"方法开始执行");
      		try {
      			//执行目标方法
      			Object rs = jp.proceed();
      			log.info(jp.getSignature().getName()+"方法正常执行完");
      			return rs;
      		} catch (Exception e) {
      			log.error("调用"+jp.getTarget()+"的"+jp.getSignature().getName()
      					+"方法发生异常"+e);
      			throw e;
      		}finally {
      			log.info(jp.getSignature().getName()+"方法执行完");
      		}
      	}
      }
    
  3. 找到spring的配置文件,开启aspectj注解

    <!--开启aspectJ注解扫描-->
        <aop:aspectj-autoproxy/>
    

ps:Spring整合junit

  1. 导入Spring-text和junit依赖

    <!--spring-test: 整合测试-->
    <dependency>
       <groupId>org.springframework</groupId>
       <artifactId>spring-test</artifactId>
       <version>5.2.15.RELEASE</version>
    </dependency>
    
  2. 在测试类上添加两个注解: 创建Spring容器, 把Spring容器bean注入到测试类

    //测试类在spring环境下运行, 创建一个Spring容器
    @RunWith(SpringJUnit4ClassRunner.class)
    //加载spring配置文件:创建一个Spring容器
    @ContextConfiguration("classpath:beans.xml")  //指定配置文件
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值