spring AOP 编程式应用

一、spring AOP 和 AspectJ

spirng AOP: 是基于对象代理模式进行织入逻辑代码,但对于static和final方法上应用织入是无法做到的
AspectJ :其是一个独立的在编辑期进行逻辑代码的织入框架,不受限于必须获取代理

二、AOP织入

1. Advice、Pointcut、Advisor、ProxyFactory

Advice (通知)是AOP联盟定义的一个接口,描述了连接点做什么,为切面增强提供织入接口。编写逻辑代码的基类
Pointcut (切点)决定Advice通知应该作用于哪个连接点。也就是说这些连接点集合(决定切入的方法)是通过Pointcut来决定的
Advisor (通知器)是对Advice和Pointcut的整合,作为IoC容器使用AOP的基础设施。所有
ProxyFactory(生成代理对象的工厂类)可以让我们通过编程式的方法实现spirng AOP功能
在spring中有三个代理工厂类,除了上面提到的还有ProxyFactoryBean(声明式应用)、AspectJProxyFactory(AspectJ应用),它们都继承了ProxyCreatorSupport类

2. 应用演示

目标类,提供切入点

class TargetImpl {
    public void print() {
        System.out.println("this is target");
    }
}
MethodInterceptor

MethodInterceptor是一个最基础的继承自->Interceptor->Advice的通知类。ProxyFactory生成bean代理有jdk proxy和Cglib两种方式,但spirng把它们的回调都统一封装,回调执行MethodInterceptor的invoke方法
具体封装在了ReflectiveMethodInvocation里,执行process来调起invoke

    private static void basics() {

        Advice advice = (MethodInterceptor) (invocation) -> {
            System.out.println("enter advice->interceptor->methodInterceptor");
            return invocation.proceed();
        };


        Pointcut pointcut = new Pointcut() {
            @Override
            public ClassFilter getClassFilter() {
                return ClassFilter.TRUE;
            }

            @Override
            public MethodMatcher getMethodMatcher() {
                return MethodMatcher.TRUE;
            }
        };
        Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);

        ProxyFactory proxyFactory = new ProxyFactory(new TargetImpl());
        proxyFactory.addAdvisor(advisor);

        TargetImpl target = (TargetImpl) proxyFactory.getProxy();
        target.print();
    }

代码中出现的DefaultPointcutAdvisor是spirng提供的一个默认通知器

MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor
  private static void before() {
        Advice advice = new MethodBeforeAdviceInterceptor((method, objects, o) -> System.out.println("enter before advice"));
        ProxyFactory proxyFactory = new ProxyFactory(new TargetImpl());
        proxyFactory.addAdvice(advice);

        TargetImpl target = (TargetImpl) proxyFactory.getProxy();
        target.print();

    }

   private static void after() {

        Advice advice = new AfterReturningAdviceInterceptor((rv, method, objects, o) -> System.out.println("enter after advice"));
        ProxyFactory proxyFactory = new ProxyFactory(new TargetImpl());
        proxyFactory.addAdvice(advice);

        TargetImpl target = (TargetImpl) proxyFactory.getProxy();
        target.print();


    }

ProxyFactory虽然可以直接添加Advice,但这并不表示它不需要Ponitcut的实现。阅读add方法源码可以看到它会生成一个默认的DefaultPointcutAdvisor添加在addAdvisor列表里

@Override
    public void addAdvice(int pos, Advice advice) throws AopConfigException {
        Assert.notNull(advice, "Advice must not be null");
        if (advice instanceof IntroductionInfo) {
            // We don't need an IntroductionAdvisor for this kind of introduction:
            // It's fully self-describing.
            addAdvisor(pos, new DefaultIntroductionAdvisor(advice, (IntroductionInfo) advice));
        }
        else if (advice instanceof DynamicIntroductionAdvice) {
            // We need an IntroductionAdvisor for this kind of introduction.
            throw new AopConfigException("DynamicIntroductionAdvice may only be added as part of IntroductionAdvisor");
        }
        else {
            addAdvisor(pos, new DefaultPointcutAdvisor(advice)); //创建默认Advisor
        }
    }
AspectJExpressionPointcut

spring通过AspectJExpressionPointcut来定义实现AspectJ中的切点语言

 private static void aspectjBefore() {
        TargetImpl target = new TargetImpl();
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression("execution( * com.programmatic.springprogrammatic.TargetImpl.print(..) )");
        Advice advice = new MethodBeforeAdviceInterceptor(new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] args, Object target) throws Throwable {
                System.out.println("enter before advice");
            }
        });

        Advisor advisor = new DefaultPointcutAdvisor(pointcut, advice);
        ProxyFactory proxyFactory = new ProxyFactory(target);
        proxyFactory.addAdvisor(advisor);


        TargetImpl proxyTarget = (TargetImpl) proxyFactory.getProxy();
        proxyTarget.print();

    }

结语

spring AOP可以说是通过两个流程来实现对代码的切入和执行逻辑代码。
(1)通知器的装配;spring AOP会把要切入点的位置和逻辑代码封装为一个标准调用流程。
(2)生成代理类的时候注入通知器;这样代理类在回调方法时就会运行切入逻辑代码了。
编程式的实现spring AOP是最基础的运用,它可以更好的使我们看到实现spring AOP装配过程,为更好的理解spring AOP作为一个基础篇

github地址:https://github.com/lotusfan/spring-programmatic ->ProxyFactoryTest

你可能感兴趣的:(spring AOP 编程式应用)