• spring源码 - AOP原理理解


    AOP使用

    1.我们都知道我们在使用spring aop时需要在@configuration类上增加@EnableAspectJAutoProxy

    2.然后在准备AOP类就可以对相应类的方法进行aop

    @Component

    @Aspect

    public class MyAspect {

    @Pointcut("execution(* com.my.service.*.*(..))")

    public void aspect(){

    System.out.println("aspect");

    }

    @Before("aspect()")

    public void myBefore(JoinPoint joinPoint) {

    System.out.println(" before "+joinPoint);

    }

    }

    原理分析

    1.首先我们看@EnableAspectJAutoProxy类代码

    @Target(ElementType.TYPE)

    @Retention(RetentionPolicy.RUNTIME)

    @Documented

    @Import(AspectJAutoProxyRegistrar.class)

    public @interface EnableAspectJAutoProxy {

    boolean proxyTargetClass() default false;

    boolean exposeProxy() default false;

    }

    从上面的代码可以看出import了AspectJAutoProxyRegistrar这个类

    2.查看AspectJAutoProxyRegistrar类代码

    class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

    @Override

    public void registerBeanDefinitions(

    AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

    AnnotationAttributes enableAspectJAutoProxy =

    AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);

    if (enableAspectJAutoProxy != null) {

    if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {

    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);

    }

    if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {

    AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);

    }

    }

    }

    }

    从此代码可以看出类继承了ImportBeanDefinitionRegistrar 接口,而在@Import处理中其有一个处理过程会对类进行处理,主要是调用registerBeanDefinitions,主要利用他可以在beanfactory中注册新类的beandefinition,我们可以 AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry)向以查找此代码,可以找到如下代码:

    public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(

    BeanDefinitionRegistry registry, @Nullable Object source) {

    return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);

    }

    发现此代码注册了AnnotationAwareAspectJAutoProxyCreator类beandefinition

    3.查看AnnotationAwareAspectJAutoProxyCreator类的关系图

     

    从上图中可以发现此类是beanPostProcessor的继承类,我们知道bean在实例化过程中会调用postProcessBeforeInstantiation、postProcessAfterInitialization方法,而我们这里逻辑先在postProcessBeforeInstantiation方法把有@Aspect注解类放入advisedBeans中

    public Object postProcessBeforeInstantiation(Class beanClass, String beanName) {

    Object cacheKey = getCacheKey(beanClass, beanName);

    if (!StringUtils.hasLength(beanName) || !this.targetSourcedBeans.contains(beanName)) {

    if (this.advisedBeans.containsKey(cacheKey)) {

    return null;

    }

    if (isInfrastructureClass(beanClass) || shouldSkip(beanClass, beanName)) {

    this.advisedBeans.put(cacheKey, Boolean.FALSE);

    return null;

    }

    }

    然后通过postProcessAfterInitialization中调用wrapIfNecessary方法来实现

    protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {

    if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {

    return bean;

    }

    if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {

    return bean;

    }

    if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {

    this.advisedBeans.put(cacheKey, Boolean.FALSE);

    return bean;

    }

    Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);

    if (specificInterceptors != DO_NOT_PROXY) {

    // advisedBeans记录了某个Bean已经进行过AOP了

    this.advisedBeans.put(cacheKey, Boolean.TRUE);

    Object proxy = createProxy(

    bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));

    this.proxyTypes.put(cacheKey, proxy.getClass());

    return proxy;

    }

    this.advisedBeans.put(cacheKey, Boolean.FALSE);

    return bean;

    }

    通过通调用getAdvicesAndAdvisorsForBean这方法实现某个bean是否被带有注解@Aspect类给AOP了,然后通过调用createProxy方法生成代理类JdkDynamicAopProxy

    @Override

    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {

    if (!NativeDetector.inNativeImage() &&

    (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {

    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.");

    }

    if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {

    return new JdkDynamicAopProxy(config);

    }

    return new ObjenesisCglibAopProxy(config);

    }

    else {

    return new JdkDynamicAopProxy(config);

    }

    }

    如果某个类被AOP了,在调用方法时只能调用此类的实现接口中的方法

    public Object getProxy(@Nullable ClassLoader classLoader) {

    if (logger.isTraceEnabled()) {

    logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());

    }

    return Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this);

    }

    然后实际调方法时主要是通过JdkDynamicAopProxy的invoke方法

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    Object oldProxy = null;

    boolean setProxyContext = false;

    TargetSource targetSource = this.advised.targetSource;

    Object target = null;

    try {

    if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {

    return equals(args[0]);

    }

    else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {

    return hashCode();

    }

    else if (method.getDeclaringClass() == DecoratingProxy.class) {

    return AopProxyUtils.ultimateTargetClass(this.advised);

    }

    else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&

    method.getDeclaringClass().isAssignableFrom(Advised.class)) {

    return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);

    }

    Object retVal;

    if (this.advised.exposeProxy) {

    // Make invocation available if necessary.

    oldProxy = AopContext.setCurrentProxy(proxy);

    setProxyContext = true;

    }

    target = targetSource.getTarget();

    Class targetClass = (target != null ? target.getClass() : null);

    List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

    if (chain.isEmpty()) {

    Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);

    retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);

    }

    else {

    MethodInvocation invocation =

    new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);

    retVal = invocation.proceed();

    }

    // Massage return value if necessary.

    Class returnType = method.getReturnType();

    if (retVal != null && retVal == target &&

    returnType != Object.class && returnType.isInstance(proxy) &&

    retVal = proxy;

    }

    else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {

    throw new AopInvocationException(

    "Null return value from advice does not match primitive return type for: " + method);

    }

    return retVal;

    }

    finally {

    if (target != null && !targetSource.isStatic()) {

    // Must have come from TargetSource.

    targetSource.releaseTarget(target);

    }

    if (setProxyContext) {

    // Restore old proxy.

    AopContext.setCurrentProxy(oldProxy);

    }

    }

    }

  • 相关阅读:
    10.23归并排序
    【JAVA】String类
    win11怎么更新22H2?不要错过这两个Win11升级22H2的好方法!
    java的amazonaws接口出现无法执行http请求:管道中断
    vue3 路由新玩法useRoute 和useRouter
    使用Python命令行优美打印json文件
    HTML+CSS+JS制作结婚邀请函代码(程序员专属情人节表白网站)
    2022年最新Vue常见基础面试题(看这一篇就够了)
    Git学习笔记
    linux卸载mysql5.7
  • 原文地址:https://blog.csdn.net/lin000_0/article/details/128195182