spring-AOP

2020-03-13  本文已影响0人  格林哈

1. AOP

1.1 静态AOP

1.2 动态AOP

1.3 java平台上AOP实现机制

1.4 AOP成员

2 spring AOP

2.1 spring AOP 实现机制

  1. 描述: SpringAOP属于第二代AOP,采用动态代理机制和动态字节码生成技术实现。动态代理机制和字节码生成都是在运行期间为目标对象生成一个代理对象,而将横切逻辑织入到这个代理对象中,系统最终使用的是织入了横切逻辑的代理对象,而不是真正的目标对象

  2. 代理模式:: Spring AOP本质上就是采用代理机制实现的代理模式参考

  3. 动态代理

    • JDK1.3以后引入动态代理机制,我们可以为指定的接口在系统运行期间动态的生成代理对象。
    • InvocationHandler就是我们实现横切逻辑的地方,它是横切逻辑的载体,作用跟Advice是一样的。
    • 动态代理的不足: 动态代理机制只能对实现了相应Interface的类使用如果某个类没有实现任何的Interface,就无法使用动态代理机制为其生成相应的动态代理对象
package com.mg.springjiemi.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class SubjectInvocationHadndler implements InvocationHandler {
   private  Object target;
   public SubjectInvocationHadndler(Object target) {
       this.target = target;
   }
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       try{
           System.out.println("-----Before Advice ------");
           if(method.getName().equals("request")){
               System.out.println("先跟秘书交谈,安全代理,虚拟代理,远程代理");
           }
           return method.invoke(target,args);
//            System.out.println("----- After returning advice -----");
       }catch (Exception e) {
           System.out.println("-----After throwing advice ------");
           return null;
       } finally {
           System.out.println("-----After advice ------");
       }
   }
}


package com.mg.springjiemi.proxy;
import java.lang.reflect.Proxy;
public class InvocationHandlerClient {
   public static void main(String[] args) {
       ISubject subject = (ISubject) Proxy.newProxyInstance(ISubject.class.getClassLoader(),new Class[]{ISubject.class},new SubjectInvocationHadndler(new SubjectImpl()));
       String value = subject.request();
       System.out.println(value);
   }
}

控制台输出:
-----Before Advice ------
先跟秘书交谈,安全代理,虚拟代理,远程代理
-----After advice ------
跟老板交谈
  1. 默认情况下,如果SpringAOP发现目标对象实现了相应Interface,则采用动态代理机制为其生成代理对象实例。而如果目标对象没有实现任何Interface,SpringAOP会尝试使用一个称为CGLIB
  2. 动态字节码生成
    • 原理: 对目标对象进行继承扩展,为其生成相应的子类,而子类可以通过覆写来扩展父类的行为,只要将横切逻辑的实现放到子类中,然后让系统使用扩展后的目标对象的子类,达到与代理模式相同效果。
    • 缺点: 无法对final方法进行覆盖
    • 代码示例

package com.mg.springjiemi.proxy.cglib;
public class SubjectImpl  {
    public String request() {
        return "跟老板交谈";
    }
}

package com.mg.springjiemi.proxy.cglib;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class SubjectCallback implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        try{
            System.out.println("-----Before Advice ------");
            if(method.getName().equals("request")){
                System.out.println("先跟秘书交谈,安全代理,虚拟代理,远程代理");
            }
            return methodProxy.invokeSuper(o,objects);
//            System.out.println("----- After returning advice -----");
        }catch (Exception e) {
            System.out.println("-----After throwing advice ------");
            return null;
        } finally {
            System.out.println("-----After advice ------");
        }
    }
}

package com.mg.springjiemi.proxy.cglib;
import net.sf.cglib.proxy.Enhancer;
public class Client {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(SubjectImpl.class);
        enhancer.setCallback(new SubjectCallback());
        SubjectImpl proxy = (SubjectImpl) enhancer.create();
        String value = proxy.request();
        System.out.println(value);
    }
}
控制台输出:
-----Before Advice ------
先跟秘书交谈,安全代理,虚拟代理,远程代理
-----After advice ------
跟老板交谈
    

3 三种Spring AOP的使用方式

3.1 Spring AOP 1.x版本发布的基于接口定义的Advice声明方式。

3.2 基于Schema的AOP,Spring 2.0发布之后增加的Spring AOP使用方式

3.3 @AspectJ形式的AOP 在Spring 2.0发布之后新增加的一种Spring AOP使用方式

4 AspectJ形式的AOP使用

4.1 @AspectJ形式Pointcut

详细使用参考 开涛博客

  1. Pointcut Expression
    • @Pointcut(标志符(表达式))
  2. Pointcut Signature 具体化为一个方法定义
    • 返回类型必须是void
    • public型的Pointcut Signature可以在其他Aspect定义中引用
    • private则只能在当前Aspect定义中引用
    • 可以将Pointcut Signature作为相应Pointcut-Expression的标志符,在Pointcut-Expression的定义中取代重复的Pointcut表达式定义
    @Pointcut("execution(* com.lcw.one.util.basetkmybatis.BaseConsumerController+.*(..)) || execution(* com.lcw.one.main.controller.*.*(..))")
    public void webLog(){}

    @Pointcut("webLog()")
    public void webLog2(){}

  1. Pointcut 标志符
    • execution
      • execution (modifiers-pattern? ret-type-pattern declaring-type-pattern?
        name-pattern (param-pattern) throws-pattern?)
      • execution(<修饰符模式>?<返回类型模式><方法所在类的全路径名>?<方法名模式>(<参数模式>)<异常模式>?) 方法的返回类型、方法名以及参数部分的匹配模式是必须指定的
      • execution通配符
        • * 可以用于任何部分的匹配模式中,可以匹配相邻的多个字符,即一个Word
        • .. 通配符可以在两个位置使用,在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
        • + 配指定类型的子类型;仅能作为后缀放在类型模式后边。
      • within 匹配指定类型下所有的Joinpoint
        • SpringAOP只支持方法级别的Joinpoint,所以,在我们为within指定某个类后,它将匹配指定类所声明的所有方法执行
      • this spring-aop匹配目标对象的代理对象, AspectJ中代调用方法一方所在的对象
      • target spring-aop匹配目标对象,AspectJ中被调用方法所在的对象
      • args 匹配拥有指定参数类型、指定参数数量的,会在运行期间动态检查参数的类型。
      • @within 匹配持有指定注解类型内的方法,静态匹配
      • @target 匹配目标对象持有指定的注解,动态匹配
      • @args 匹配方法传入的参数持有指定注解的执行;
      • @annotation:匹配方法持有指定注解的方法;

public boolean login (object user); 传入 mg.User 对象。
execution (* * (User)) 匹配不到 静态pointcut
args(mg.User) 可以 动态pointcut

4.2 @AspectJ形式的Advice

// 案例
@Aspect("perthis(this(mg.Apple))")
@Component
public class WebLogAspect {
    private Logger logger = LoggerFactory.getLogger(WebLogAspect.class);


    @Pointcut("this(mg.Apple)")
    public void webLog(){}
    }
    
    @Pointcut("webLog()")
    public void webLog2(){}

5 AOP 实现

5.1 AnnotationAwareAspectJAutoProxyCreator

上一篇下一篇

猜你喜欢

热点阅读