springAOP

springAOP

前言:
  • 静态代理
    静态代理类:
    1、原则:和目标方法类功能一致且和目标类实现同样的接口。
    2、缺点:

    • 往往在开发我们自己写的不仅仅是一个业务,两个业务,而我们的业务会有很多,如果每一个业务开发一个静态代理类,不仅没有减少我们的工作量,而且让我们的工作量多了很多。
    • 如何解决这个问题?能不能为我们现有的业务层动态的创建代理类,通过动态代理去解决我们现有的业务层中的业务代码冗余问题。
  • 动态代理

    通过jdk提供的Proxy类,动态为现有的业务生成代理类。

代码示例:

/**
 * JDK中的动态代理
 * @author MOTUI
 *
 */
public class TestUserServiceImplDynamicProxy {
    public static void main(String[] args) {
        final UserService userService = new UserServiceImpl();
        //使用JDK提供的Proxy对象,用来产生动态代理类
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        Class<?>[] interfaces = {UserService.class};
        InvocationHandler h = new InvocationHandler() {
            //参数1:生成的代理对象
            //参数2:当前调用的方法对象
            //参数3:当前带哦啊用方法参数
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
                try {
                    System.out.println("开启事务");
                    //调用真正的业务逻辑
                    Object invoke = method.invoke(userService, args);
                    System.out.println("提交事务");
                    return invoke;
                } catch (Exception e) {
                    System.out.println("回滚事务");
                    e.printStackTrace();
                }
                return null;
            }
        };
        //参数1:当前线程的类加载器   加载.class文件
        //参数2:生成代理的对象的目标类的接口类型
        //参数3:当通过代理对象去调方法时,会优先进入InvocationHander类的invoke方法
        UserService userServiceProxy =  (UserService) Proxy.newProxyInstance(loader, interfaces, h);//返回静态代理对象
        //userServiceProxy.save();
        String query = userServiceProxy.query("小王");
        System.out.println(query);
    }
}

学习AOP需要知道几个重要的概念:

  • 通知(Advice):处理目标方法以外的操作都称之为通知
  • 切入点(PointCut):要为哪些类中的哪些方法加入通知
  • 切面(Aspect): 通知 + 切入点

    • 前置通知:
      代码:

      public class RecordMethodNameBeforeAdvice implements MethodBeforeAdvice {
      
          /**
           * 参数1:当前目标类中调用的方法对象
           * 参数2:当前目标类中调用的方法的参数
           * 参数3:目标对象
           */
          @Override
          public void before(Method method, Object[] args, Object target)
                  throws Throwable {
              System.out.println("当前执行的方法:"+method.getName());
          }
      
      }

      配置文件:

          <!-- 管理Bean -->
          <bean id="userService" class="com.motui.first.UserServiceImpl"/>
          <!-- 配置通知 -->
          <bean id="methodBeforeAdvice" class="com.motui.first.RecordMethodNameBeforeAdvice"></bean>
          <!-- 配置切面 -->
          <aop:config>
              <!-- 配置切入点 
              expression:指定哪个类的那个方法需要加入通知-->
              <aop:pointcut expression="execution(* com.motui.first.UserServiceImpl.*(..))" id="pc"/>
              <!-- 组合切入点和通知 -->
              <!-- 
                  advice-ref:告诉当前切面使用的是哪个通知 书写通知bean的id
                  pointcut-ref:当前通知加入哪个切入点
               -->
              <aop:advisor advice-ref="methodBeforeAdvice" pointcut-ref="pc"/>
          </aop:config>
    • 后置通知:
      代码:

      public class MyAfter implements AfterReturningAdvice ,ThrowsAdvice {
      //参数1: 目标类中当前执行的方法的返回值
      //参数2: 目标类中当前执行的方法对象
      //参数3: 目标类中当前执行的方法的参数
      //参数4: 目标对象
      @Override
      public void afterReturning(Object result, Method m, Object[] args,
              Object traget) throws Throwable {
          System.out.println("返回值:"+result);
          System.out.println("当前目标类的目标方法"+m.getName());
          System.out.print("参数列表:");
          if (args.length>0) {
              for (Object object : args) {
                  System.out.println(object);
              }
          }else{
              System.out.println("参数为空");
          }
          System.out.println("目标:"+traget);
      }
      
      //出现异常时进入的通知方法
      public void afterThrowing(Method method, Object[] args, Object target,Exception ex){
          System.out.println("异常通知的方法的名称: "+method.getName());
          System.out.println("异常通知的方法的参数: "+args);
          System.out.println("异常通知的目标对象"+target);
          System.out.println("异常通知的异常的信息 :" +ex.getMessage());
      }
      }

      配置文件:

      <!-- 管理bean -->             
      <bean id="deptService" class="com.motui.after.DeptServiceImpl"/>
      <bean id="myAfter" class="com.motui.after.MyAfter"/>
      <!-- 配置切入点 -->
      <aop:config>
      <aop:pointcut expression="execution(* com.motui.after.DeptServiceImpl.*(..))" id="pc"/>
      <aop:advisor advice-ref="myAfter" pointcut-ref="pc"/>
      </aop:config>
    • 环绕通知:
      代码:

      /**
       * 记录运行时长
       * @author MOTUI
       *
       */
      public class TestAroundAOP implements MethodInterceptor{
      
          @Override
          public Object invoke(MethodInvocation mi) throws Throwable {
              System.out.println("记录运行时长");
              long start = new Date().getTime();
              Object proceed = mi.proceed();//返回值为目标方法的返回值,这个返回值在通知类中返回
              long end = new Date().getTime();
              System.out.println("运行时长:"+(end-start));
              return proceed;
          }
      
      }

      配置文件:

          <!-- 管理Service -->
      <bean id="addressService" class="com.motui.around.AddressServiceImpl"/>
      
      <bean id="testAroundAOP" class="com.motui.around.TestAroundAOP"/>
      <!-- 配置切入点 -->
      <aop:config>
          <aop:pointcut expression="execution(* com.motui.around.AddressServiceImpl.*(..))" id="pc"/>
          <aop:advisor advice-ref="testAroundAOP" pointcut-ref="pc"/>
      </aop:config>
    • 异常通知:

      代码在后置通知中。

    • execution表达式:

      execution(返回值类型 包名.类名.方法名(参数列表))
      示例:
              execution(* com.motui.service.impl.UserServiceImpl.save(..))
                  返回值:任意
                  包:com.motui.service.impl
                  类:UserServiceImpl
                  方法:save
                  参数:任意
      
              execution(* com.motui.service.impl.UserServiceImpl.*(..))
                  返回值:任意
                  包:com.motui.service.impl
                  类:UserServiceImpl
                  方法:任意方法
                  参数:任意
      

在spring中有两种代理模式(JDK中的proxy和CGLIB):
在spring配置文件中可以通过proxy-target-class属性指定,true是CGLIB代理;false是Proxy代理

总结:

    Spring的核心思想
    IOC:控制反转    DI:依赖注入
    AOP:面向切面的编程思想
            AOP:通过动态为现有项目中的目标类创建代理对象,解决项目中的一些通用问题。
            AOP几个重要概念:
            通知(Advice):除了目标方法以外的操作称之为通知
            切入点(Pointcut):项目中的哪些类的哪些方法需要加入通知
            切面(Aspect):通知 + 切入点
    AOP的底层实现
            1、JDK的动态代理  Proxy   基于接口生成的代理
            2、Spring CGBIL (CGLIB用来生成动态代理) 基于实现类生成的代理
            3、JDK Proxy和CGLIB生成代理的区别?
                Proxy根据接口生成动态代理对象,产生对象的返回值是接口类型
                CGLIB根据实现类生成代理对象,产生对象的返回值是实现类类型(目标类型)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值