11分钟浅析Spring AOP


11分钟浅析Spring AOP

既然认准这条路,何必去打听要走多久


AOP是Spring框架面向切面的编程思想,AOP采用一种称为“横切”的技术,将涉及多业务流程的通用功能抽取并单独封装,形成独立的切面,在合适的时机将这些切面横向切入到业务流程指定的位置中。

1.AOP名词解释

  • JoinPoint(连接点):目标对象中,所有可以增强的方法,就是spring允许你是通知(Advice)的地方,那可就真多了,基本每个方法的前、后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点。

  • Pointcut(切入点):目标对象中,已经被增强的方法。调用这几个方法之前、之后或者抛出异常时干点什么,那么就用切入点来定义这几个方法。

  • Advice(通知/增强) :增强方法的代码、想要的功能。

  • Target(目标对象):被代理对象,被通知的对象,被增强的类对象。

  • Weaving(织入):将通知应用到连接点形成切入点的过程

  • Proxy(代理):将通知织入到目标对象之后形成的代理对象

  • aspect(切面):切入点+通知—通知(Advice)说明了干什么的内容(即方法体代码)和什么时候干(什么时候通过方法名中的before,after,around等就能知道),二切入点说明了在哪干(指定到底是哪个方法),切点表达式等定义。

2.两种代理方式

2.1.JDK动态代理

主要是代理接口;

jdk的动态代理调用了Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法;

代理类需要继承java.lang.reflect.invocationHandle 接口;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.aspect.MyAspect;
import com.jdk.*;

public class JdkProxy implements InvocationHandler {

    private Userdao userdao;
    public Object creatProxy(Userdao userdao){
        this.userdao=userdao;
        //类加载器
        ClassLoader classLoader=JdkProxy.class.getClassLoader();
        //获取所有目标对象所有接口
        Class[] clazz=userdao.getClass().getInterfaces();
        //返回代理后对象
        return Proxy.newProxyInstance(classLoader, clazz, this);
    }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        MyAspect myAspect=new MyAspect();
        myAspect.check();
        Object obj=method.invoke(userdao, args);
        myAspect.log();
        return obj;
    }
}

2.2 CGLIB代理

主要是代理类。

package com.proxy;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.cglib.proxy.Enhancer;
import com.aspect.*;

public class CglibPoxy implements MethodInterceptor {
    public Object crearProxy(Object target){
        //创建动态对象
        Enhancer enhancer=new Enhancer();
        //确定要增强胡类及设置父类
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }

    public Object intercept(Object proxy, Method method, Object[] args,
            MethodProxy methodProxy) throws Throwable {

        MyAspect myAspect=new MyAspect();
        myAspect.check();
        Object object= methodProxy.invokeSuper(proxy, args);
        myAspect.log();
        return object;
    }
}

3.Spring AOP的实现

3.1.所需类包:

  • spring 核心包
  • spring-aop-4.3-release.jar
  • aopalliance-1.0.jar

    主要是通过 ProxyFactoryBean 来创建代理实例

3.2.实现:

  • Myaspect切面类:

      package com.aspect;
      import org.aopalliance.intercept.MethodInterceptor;
      import org.aopalliance.intercept.MethodInvocation;
      public class Myaspect implements MethodInterceptor {
          public Object invoke(MethodInvocation method) throws Throwable {
              check();
              Object object= method.proceed();
              log();
              return object;
          }
    
      public void check(){
          System.out.println("模拟检查权限。。");
      }
      public void log(){
          System.out.println("模拟检查日志。。");
      }

    }

  • application配置文件:

      
      
          
          
          
              
              
              
          
      

4.Aspectj 开发

主要包类:

  • spring 核心包
  • spring-aop-4.3-release.jar
  • aspectjweaver-1.8.10.jar

4.1 基于XML声明

实现:

  • applicationContext配置文件:

      <?xml version="1.0" encoding="UTF-8"?>
       <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:aop="http://www.springframework.org/schema/aop"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/aop
              http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
    
          <bean id="userdao" class="com.dao.Userdao"></bean>
          <bean id="myaspect" class="com.aspect.Myaspect"></bean>
          <aop:config>
              <aop:aspect ref="myaspect">
                  <aop:pointcut id="pointcut1" expression="execution(* com.dao.*.*(..))"></aop:pointcut>
                  <aop:before method="mybefore" pointcut-ref="pointcut1" />
                  <aop:after-returning method="myafterRetern" returning="returnVal" pointcut-ref="pointcut1"/>
                  <aop:around method="myAround" pointcut-ref="pointcut1" />
                  <aop:after-throwing method="mythrow" throwing="e" pointcut-ref="pointcut1"/> 
                  <aop:after method="myAfter" pointcut-ref="pointcut1" />    
              </aop:aspect>
          </aop:config>
      </beans>
  • Aspect切面类:

      package com.aspect;
      import org.aspectj.lang.JoinPoint;
      import org.aspectj.lang.ProceedingJoinPoint;
      public class Myaspect {
          //前置通知
          public void mybefore(JoinPoint joinPoint){
              System.out.println("模拟前置执行通知。。");
              System.out.println("执行的目标类: "+joinPoint.getTarget());
              System.out.println("目标方法: "+joinPoint.getSignature().getName());
              System.out.println("-----------------");
          }
          //后置通知
          public void myafterRetern(JoinPoint joinPoint,Object returnVal){
              System.out.println(returnVal);
              System.out.println("模拟后置记录日志");
              System.out.println("目标方法: "+joinPoint.getSignature().getName());
              System.out.println("-----------------");
          }
    
          //环绕通知
          public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
              System.out.println("-----------------");
              System.out.println("环绕前置开始:---");
              Object object=proceedingJoinPoint.proceed();
              System.out.println("环绕后置结束:---");
              System.out.println("-----------------");
              return object;
          }
    
          //异常通知
          public void mythrow(JoinPoint joinPoint,Throwable e){
              System.out.println("异常发生: "+e.getMessage());
              System.out.println("-----------------");
          }
          //最终通知
          public void myAfter(JoinPoint joinPoint){
              System.out.println("最终通知。。");
              System.out.println("-----------------");
          }
      }

4.1 基于注解声明

  • applicationContext配置文件:

      <?xml version="1.0" encoding="UTF-8"?>
       <beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:aop="http://www.springframework.org/schema/aop"
          xmlns:context="http://www.springframework.org/schema/context"
          xsi:schemaLocation="http://www.springframework.org/schema/beans
              http://www.springframework.org/schema/beans/spring-beans.xsd
              http://www.springframework.org/schema/aop
              http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
              http://www.springframework.org/schema/context
              http://www.springframework.org/schema/context/spring-context-4.3.xsd">
    
          <context:component-scan base-package="com" />
          <aop:aspectj-autoproxy />
      </beans>

*Aspect切面类:

    package com.aspect;
    import org.aspectj.lang.JoinPoint;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.*;
    import org.springframework.stereotype.Component;

    @Aspect
    @Component
    public class Myaspect {
        //定义切入点
        @Pointcut("execution(* com.dao.*.*(..))")
        private void mypointcut() {}

        //前置通知
        @Before("mypointcut()")
        public void mybefore(JoinPoint joinPoint){
            System.out.println("模拟前置执行通知。。");
            System.out.println("执行的目标类: "+joinPoint.getTarget());
            System.out.println("目标方法: "+joinPoint.getSignature().getName());
            System.out.println("-----------------");
        }

        //后置通知
        @AfterReturning(value="mypointcut()",returning="returnVal")
        public void myafterRetern(JoinPoint joinPoint,Object returnVal){
            System.out.println(returnVal);
            System.out.println("模拟后置记录日志");
            System.out.println("目标方法: "+joinPoint.getSignature().getName());
            System.out.println("-----------------");
        }

        //环绕通知
        @Around("mypointcut()")
        public Object myAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
            System.out.println("-----------------");
            System.out.println("环绕前置开始:---");
            Object object=proceedingJoinPoint.proceed();
            System.out.println("环绕后置结束:---");
            System.out.println("-----------------");
            return object;
        }

        //异常通知
        @AfterThrowing(value="mypointcut()",throwing="e")
        public void mythrow(JoinPoint joinPoint,Throwable e){
            System.out.println("异常发生: "+e.getMessage());
            System.out.println("-----------------");
        }

        //最终通知
        @After("mypointcut()")
        public void myAfter(JoinPoint joinPoint){
            System.out.println("最终通知。。");
            System.out.println("-----------------");
        }
    }

文章作者: Athink
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Athink !
评论
 上一篇
11分钟学习JavaWeb中Listener和Filter 11分钟学习JavaWeb中Listener和Filter
JavaWeb中Listener是个监听器,能够监听某一个事件的发生和状态的改变和,而Filter呢则是个过滤器,能够对客户端发出来的请求进行过滤
2020-03-11
下一篇 
阿里云服务器¥67/年 阿里云服务器¥67/年
阿里云服务器三年203元,平均每年67元,每月6元,比市面上所有的虚拟主机都还要便宜,同时服务器可做的事情更多,可自定义搭配部署等
2020-03-06
  目录