MethodInterceptor

MethodInterceptor是AOP项目中的拦截器(注:不是动态代理拦截器),区别与HandlerInterceptor拦截目标时请求,它拦截的目标是方法。

实现MethodInterceptor拦截器大致也分为两种:

(1)MethodInterceptor接口;

(2)利用AspectJ的注解配置;

MethodInterceptor接口:



import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MethodInvokeInterceptor implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("before method invoke....");
        Object object = methodInvocation.proceed();
        System.out.println("after method invoke.....");
        return object;
    }
}



<!-- 拦截器 demo -->
    <bean id="methodInvokeInterceptor" class="com.paic.phssp.springtest.interceptor.method.MethodInvokeInterceptor"/>

    <aop:config>
        <!--切入点,controlller -->
        <aop:pointcut id="pointcut_test"   expression="execution(* com.paic.phssp.springtest.controller..*.*(..))" />
        <!--在该切入点使用自定义拦截器 ,按照先后顺序执行 -->
        <aop:advisor pointcut-ref="pointcut_test" advice-ref="methodInvokeInterceptor" />

    </aop:config>

    <!-- 自动扫描使用了aspectj注解的类 -->
    <aop:aspectj-autoproxy/>



执行:

spring 拦截器增加请求头参数 spring拦截器实现原理_spring 拦截器增加请求头参数

AspectJ的注解



import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class AutoAspectJInterceptor {

    @Around("execution (* com.paic.phssp.springtest.controller..*.*(..))")
    public Object around(ProceedingJoinPoint point) throws Throwable{
        System.out.println("AutoAspectJInterceptor begin around......");
        Object object = point.proceed();
        System.out.println("AutoAspectJInterceptor end around......");
        return object;
    }
}



运行结果:

AutoAspectJInterceptor begin around......
>>>>:isAuthenticated=false
AutoAspectJInterceptor end around......


 

简单介绍下关键词:

AOP=Aspect Oriented Program  面向切面(方面/剖面)编程

Advice(通知):把各组件中公共业务逻辑抽离出来作为一个独立 的组件

Weave(织入) : 把抽离出来的组件(Advice),使用到需要使用该逻辑 地方的过程。

JoinPoint (连接点): Advice 组件可以weave的特征点。

PointCut(切入点):用来明确Advice需要织入的连接点

Aspect(切面):Aspect=Advice + PointCut

通知类型

@Before  在切点方法之前执行

@After  在切点方法之后执行

@AfterReturning 切点方法返回后执行

@AfterThrowing 切点方法抛异常执行

@Around环绕通知

执行顺序:

@Around环绕通知
@Before通知执行
@Before通知执行结束
@Around环绕通知执行结束
@After后置通知执行了!
@AfterReturning

切面设置:

可以使用&&、||、!、三种运算符来组合切点表达式

execution表达式:



"execution(public * com.xhx.springboot.controller.*.*(..))"



*只能匹配一级路径
..可以匹配多级,可以是包路径,也可以匹配多个参数
+ 只能放在类后面,表明本类及所有子类

within(类路径)   配置指定类型的类实例,同样可以使用匹配符



within(com.xhx.springboot..*)



@within(annotationType) 匹配带有指定注解的类(注:与上不同)



"@within(org.springframework.stereotype.Component)"



@annotation(annotationType) 匹配带有指定注解的方法



"@annotation(IDataSource)"



其中:IDataSource为自定义注解



import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface IDataSource {
    String value() default "dataSource";
}




下面分析下Spring @Aspect :

1、注册

org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator

spring 拦截器增加请求头参数 spring拦截器实现原理_spring 拦截器增加请求头参数_02

看到实现接口BeanPostProcessor,必然在初始化Bean前后,执行接口方法。

2、解析

AspectJAutoProxyBeanDefinitionParser.java#parse()方法



@Nullable
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        AopNamespaceUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext, element);
        this.extendBeanDefinition(element, parserContext);
        return null;
    }



public static void registerAspectJAnnotationAutoProxyCreatorIfNecessary(ParserContext parserContext, Element sourceElement) {
        BeanDefinition beanDefinition = AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(parserContext.getRegistry(), parserContext.extractSource(sourceElement));
        useClassProxyingIfNecessary(parserContext.getRegistry(), sourceElement);
        registerComponentIfNecessary(beanDefinition, parserContext);
    }



@Nullable
    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(BeanDefinitionRegistry registry, @Nullable Object source) {
        return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
    }



3、具体实现

上面提到实现接口BeanPostProcessor,必然在初始化Bean前后,执行接口方法。看下面时序图:

 AbstractAutoProxyCreator的postProcessAfterInitialization()方法。

spring 拦截器增加请求头参数 spring拦截器实现原理_runtime_03

DefaultAopProxyFactory.createAopProxy()方法,具体创建代理类。两种动态代理:JDK动态代理和CGLIB代理。



public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (!config.isOptimize() && !config.isProxyTargetClass() && !this.hasNoUserSuppliedProxyInterfaces(config)) {
            return new JdkDynamicAopProxy(config);
        } else {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: Either an interface or a target is required for proxy creation.");
            } else {
                return (AopProxy)(!targetClass.isInterface() && !Proxy.isProxyClass(targetClass) ? new ObjenesisCglibAopProxy(config) : new JdkDynamicAopProxy(config));
            }
        }
    }



下午有点?。。。。