spring aop

Posted fymc

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring aop相关的知识,希望对你有一定的参考价值。

一。概念

1。连接点:应用程序执行期间明确的一个点。比如方法调用,方法调用本身,类初始化和对象实例化。aop插入其他逻辑的地方。

2。通知:在特定连接点执行的代码。

3。切入点:定义何时执行通知的连接点集合。

4。切面:封装在中的通知和切入点的组合。

5。织入:在适当的位置讲切面插入到应用程序代码中的过程。编译时织入,运行时织入,加载时织入(LTW拦截底层JVM类加载器,在类加载器加载字节码时向其提供织入功能)。

6。目标对象:被代理的对象

7。引入:通过引入其他方法或字段来修改对象结构的过程。

二。类型

1。静态AOP:修改代码,编译时织入。

2。动态AOP:运行时动态织入。spring为所有被通知对象创建代理。

三。spring aop

1。第一部分是AOP内核,提供完全解耦的纯编程AOP功能。比如AOP Alliance接口,定义了一组接口来提供服务。

比如:MethodInvocation接口,用于实现方法调用连接点的环绕通知。

示例。下面是创建AOP代理的纯程序化方法。

//1.创建代理,在调用目标方法的时候实际调用的是这个代理

public class AgentDecorator implements MethodInterceptor

      public Object invoke(MethodInvocation invocation) throws Throwable

            System.out.print("James");

            object retVal = invocation.proceed();//调用被代理的方法。MethodInvocation封装被调用的方法

            System.out.print("!");

            return retVal;

     

//2.织入目标对象

public class AgentAOPDemo

      public static void main(String... args)

          Agent target = new Agent();

          ProxyFactory pf = new ProxyFactory();//核心类,整合通知和目标类,

          pf.addAdvice(new AgentDecorator());//添加代理类,后台委托给addAdvisor(),创建DefaultPointcutAdvisor实例,并应用于所有方法。

          pf.setTarget(target);//设置目标类

          Agent proxy = (Agent)pf.getProxy();

          target.speak();

          proxy.speak();          

 

2。第二部分是spring aop架构

spring AOP的核心架构基于代理

(1)JDK动态代理:目标接口实现接口时调用。

(2)CGLIB代理:目标接口未实现接口时调用。

 

2.1 Spring中的连接点

     只支持方法调用,如果需要其他使用AspectJ.

2.2 Spring中的切面

     由实现Advisor接口的实例表示。它有两个子接口:PointcutAdvisor IntroductionAdvisor。

2.3 ProxyFactory类

     控制Spring AOP中的织入和代理创建过程,ProxyFactory把代理创建过程委托给DefaultAopProxyFactory的一个实例,而该实例又进一步委托给Cglib2AopProxy或者JdkDynamicAopProxy,具体选择哪个由设置参数控制。

2.4 通知类型

(1)前置通知:实现接口 MethodBeforeAdvice 

  方法:before(Method method, Object[] args, Object target)

(2)后置返回通知:实现接口AfterReturningAdvice 在连接点的方法调用完成并返回一个值后执行后置返回通知。如果方法抛出异常就不会执行。

  方法:afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable

(3)后置通知:实现接口AfterAdvice 仅当被通知方法正常完成时才执行后置通知。及时方法异常也会执行。

(4)环绕通知:实现MethodInterceptor接口。可以指定方法执行时机,也可以绕过。

  方法:Object invoke(MethodInvocation invocation) throws Throwable

                      //前置处理逻辑

                      invocation.proceed();调用实际的方法

                      //后置处理逻辑

       

(5)异常通知:实现接口ThrowsAdvice 在方法调用抛出异常时执行

  无方法,实现该接口的类需要设置名称为afterThrowing(Exception ex) throws Throwable 或者 afterThrowing(Method method, Object args, Object target, IllegalArgumentException ex) throws Throwable.

spring在异常通知中寻找的第一个方法是一个或者多个被称为afterThrowing()的公共方法。返回类型不重要,最后为void。

(6)引入通知:实现接口IntroductionInterceptor 

三。在spring中使用顾问和切入点

通知(addAdvice)会通知目标函数的全部方法,虽然可用在调用的时候通过类型类判断,但是这种方式不太灵活。为此spring提供了顾问(addAdvisor),顾问和通知的区别是增加了切入点,也就是可以指定哪些方法需要被通知。

PointCut接口

public interface Pointcut

       ClassFilter getClassFilter();

       MethodMatcher getMethodMatcher();

public interface ClassFilter

       boolean matcher(Class<?> clazz);

public interface MethodMatcher

      boolean matcher(Method m, Class<?> targetClass);

      boolean isRuntime();  false:静态只会调用一次上面的方法    true:动态,先调用一次上面的方法进行静态检查,spring还会在每次方法调用的时候调用下面的方法进行检查。

      boolean matcher(Method m, Class<?> targetClass, Object[] args);

spring 提供了一下实现了上面接口的抽象类,以方便使用。

1.可用的切入点的实现

(1)使用StaticMethodMatcherPointcut创建静态切入点

实现了MethodMatcher和Pointcut接口

public class SimpleStaticPointcut extends staticMethodMatcherPointcut

     //判断方法

      @Override

      public boolean matcher(Method method, Class<?> cls)

            return ("sing".equals(method.getName()));

     

     //判断类

      @Override

      public ClassFilter getClassFilter()

    return cls->(cls==GoodGuitarist.class);

  

创建通知从上面的类型中生成一个通知。SimpleAdvice

调用:

Pointcut pc = new SimpleStaticPointcut();

Advice advice = new SimpleAdvice();

Advisor advisor = new DefaultPointcutAdvisor(pc, advice);//使用切入点和通知生成顾问。

ProxyFactory pf = new ProxyFactory();

pf.setAdvisor(advisor);

pf.setTarvget();

.........

(2)使用DyanmicMethodMatcherPointcut创建动态切入点

方法:

1.matches(Method method, Class<?> cls)先执行

2.matches(Method method, Class<?> cls, Object args)后执行,很明显多了参数,可以通过方法的传入参数进一步过滤。

3.ClassFilter getClassFilter()

(3)使用简单名称匹配 NameMatchMethodPointcut

NameMatchMethodPointcut pc = new NameMatchMethodPointcut();

pc.addMethodName("sing");

...

  (4) 用正则表达式 JdkRegexpMethodPointcut

JdkRegexpMethodPointcut pc = new JdkRegexpMethodPointcut();

pc.setPattern(".*sing.*"); 只通知方法名称包含sing的方法。

(5)使用AspectJ切入点表达式   AspectJExpressionPointcut

AspectJExpressionPointcut pc = new AspectJExpressionPointcut();

pc.setExpression("execution(* sing*(..))");

  (6)使用注解匹配切入点  @AdviceRequired

在要通知的方法或者类上设置这个注解

AnnotationMatchingPointcut pc = AnnotationMatchingPointcut.forMethodAnnotation(AdviceRequired.class);

 

以上是关于spring aop的主要内容,如果未能解决你的问题,请参考以下文章

源码学习之AOPSpring AOP使用

AOPSpring大法有多好约定编程

关于Spring——AOP

关于Spring——AOP

AOPspring 的AOP编程报错:[Xlint:invalidAbsoluteTypeName]error

框架 - Spring 源码一步步深入