Spring 攔截器實現+后台原理(MethodInterceptor)


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/>

執行:

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

看到實現接口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()方法。

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));
            }
        }
    }

下午有點😵。。。。

 

參考:

https://www.cnblogs.com/davidwang456/p/5633940.html

https://www.cnblogs.com/niceyoo/p/8735637.html

https://blog.csdn.net/u014634338/article/details/84144498

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM