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環繞通知
@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