spring源码阅读--aop实现原理讲解

目录
  • aop实现原理简介
  • 代理实现的处理器(BeanPostProcessor)
    • 代理实现的源头–AnnotationAwareAspectJAutoProxyCreator
    • AnnotationAwareAspectJAutoProxyCreator的继承结构
  • 代理对象(Proxy)的创建
    • 解析并缓存切面
    • 适配切面

aop实现原理简介

首先我们都知道aop的基本原理就是动态代理思想,在设计模式之代理模式中有介绍过这两种动态代理的使用与基本原理,再次不再叙述。

这里分析的是,在spring中是如何基于动态代理的思想实现aop的。为了方便了解接下来的源码分析,这里简单化了一个流程图分析aop的基本实现思想。

so,基于上面的流程,一步步分析spring源码中的aop实现方式。

采用一个简单的aop例子,利用基于注解配置方式的切面配置,分析一个简单的Before AOP例子。在spring boot下运行以下简单例子。

AOP的advisor和advice配置。

@Component
@Aspect
public class AopConfig {
    @Pointcut("execution(* com.garine.debug.testcase.model.AopObject..*(..))")
    public void mypoint(){
        //切面定义
    }
    @Before("mypoint()")
    public void doAround() throws Throwable {
        System.out.println("before logic");
    }
}

AopObject,被代理拦截对象。

@Component
public class AopObject {
    public void aoped(){
        System.out.println("logic");
    }
}

代理实现的处理器(BeanPostProcessor)

首先是第一步内容,对我们在AopConfig中的AOP配置内容进行解析并且保存到BeanFactory中,这个过程就是解析保存切面信息。

代理实现的源头–AnnotationAwareAspectJAutoProxyCreator

经过一遍的代码跟踪,我了解到注解方式的AOP配置,都离不开一个类–AnnotationAwareAspectJAutoProxyCreator,这个类继承了BeanPostProcessor接口,我们都知道BeanPostProcessor的实现类有多个执行处理节点,其中一个执行节点就是在Bean实例化之后。也就是在这个时机AnnotationAwareAspectJAutoProxyCreator拦截bean的初始化过程,根据提前解析得到的切面信息,对bean的方法进行尝试适配,如果有匹配则需要进行代理创建。

这里先分析的就是AnnotationAwareAspectJAutoProxyCreator,在bean实例化第一次查询所有切面信息时,就会解析保存Aop的信息到实例中,跟踪以下代码。

AbstractApplicationContext#refresh (上下文初始化主干方法)

AbstractApplicationContext#registerBeanPostProcessors (执行实例化并保存所有实现BeanPostProcessor接口的类)

按照上面的逻辑,registerBeanPostProcessors 会比一般的bean实例化逻辑要早执行,因此我们接下来只需要分析AnnotationAwareAspectJAutoProxyCreator的初始化过程。

AnnotationAwareAspectJAutoProxyCreator的继承结构

通过上图可以知道,AnnotationAwareAspectJAutoProxyCreator是继承了BeanfactoryAware接口,所以在实例化时,会执行setFactory方法。而所有切面信息解析的执行者BeanFactoryAspectJAdvisorsBuilderAdapter初始化的时机也是在setFactory方法。

跟踪代码如下。

AbstractAdvisorAutoProxyCreator#setBeanFactory

AnnotationAwareAspectJAutoProxyCreator#initBeanFactory

在这个方法里面会新建一个BeanFactoryAspectJAdvisorsBuilderAdapter,这个对象会根据Beanfactory内的aop配置信息,进行解析保存。但是需要注意,此时虽然新建了BeanFactoryAspectJAdvisorsBuilderAdapter对象.但是此时还不会马上解析aop配置,需要在第一次个普通bean实例化时才执行解析aop配置。解析的方法就是

BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors,会在初次执行AnnotationAwareAspectJAutoProxyCreator调用postProcessBeforeInitialization时开始执行。

protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
   super.initBeanFactory(beanFactory);
    //aspectJAdvisorsBuilder#buildAspectJAdvisors就是解析配置入口
   this.aspectJAdvisorsBuilder =
         new BeanFactoryAspectJAdvisorsBuilderAdapter(beanFactory, this.aspectJAdvisorFactory);
}

代理对象(Proxy)的创建

解析并缓存切面

上面提到继承结构图中,AnnotationAwareAspectJAutoProxyCreator是实现了InstantiationAwareBeanPostProcessor接口的,InstantiationAwareBeanPostProcessor接口定义的postProcessBeforeInitialization方法是一个可以对已经注入依赖属性的bean对象实例进行编辑操作的接口,会在

AbstractAutowireCapableBeanFactory#doCreateBean

AbstractAutowireCapableBeanFactory#initializeBean(String, Object, RootBeanDefinition)

AbstractAutowireCapableBeanFactory#applyBeanPostProcessorsBeforeInstantiation

方法中执行InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation,初次初始化缓存切面信息的话就是在这个方法里面。。

具体的调用链如上所示。这里的postProcessBeforeInstantiation方法实际上是AnnotationAwareAspectJAutoProxyCreator的实例进行调用,AnnotationAwareAspectJAutoProxyCreator实现InstantiationAwareBeanPostProcessor接口。

下面进入InstantiationAwareBeanPostProcessor#postProcessBeforeInitialization方法分析代码。

AbstractAutoProxyCreator#postProcessBeforeInstantiation

AspectJAwareAdvisorAutoProxyCreator#shouldSkip (关键代码)

进入如下代码AbstractAutoProxyCreator,这个实例也就是之前一开始初始化的AnnotationAwareAspectJAutoProxyCreator实例,进入实例的shouldSkip 方法

	@Override
	protected boolean shouldSkip(Class<?> beanClass, String beanName) {
		// TODO: Consider optimization by caching the list of the aspect names
        //预先解析缓存切面信息
		List<Advisor> candidateAdvisors = findCandidateAdvisors();
		for (Advisor advisor : candidateAdvisors) {
			if (advisor instanceof AspectJPointcutAdvisor) {
				if (((AbstractAspectJAdvice) advisor.getAdvice()).getAspectName().equals(beanName)) {
					return true;
				}
			}
		}
		return super.shouldSkip(beanClass, beanName);
	}

AnnotationAwareAspectJAutoProxyCreator#findCandidateAdvisors

方法findCandidateAdvisors代码如下,这里是预先解析缓存所有切面advisor信息,注意这一步操作是在AbstractAutoProxyCreator#postProcessBeforeInitialization处理,也就是开头提到的切面解析操作,解析完成就进行缓存。

@Override
protected List<Advisor> findCandidateAdvisors() {
   // Add all the Spring advisors found according to superclass rules.
   List<Advisor> advisors = super.findCandidateAdvisors();
   // Build Advisors for all AspectJ aspects in the bean factory.
    //这里就是前面提到的BeanFactoryAspectJAdvisorsBuilder解析所有切面信息的调用点
   advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
   return advisors;
}

然后继续在这里先提前看一下是如何解析aop配置的。跟踪BeanFactoryAspectJAdvisorsBuilder#buildAspectJAdvisors

public List<Advisor> buildAspectJAdvisors() {
   List<String> aspectNames = null;
   synchronized (this) {
      aspectNames = this.aspectBeanNames;
      if (aspectNames == null) {
         List<Advisor> advisors = new LinkedList<Advisor>();
         aspectNames = new LinkedList<String>();
          //查询出Beanfactory中所有已经注册的BeanName
         String[] beanNames =
               BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.beanFactory, Object.class, true, false);
         for (String beanName : beanNames) {
            if (!isEligibleBean(beanName)) {
               continue;
            }
            // We must be careful not to instantiate beans eagerly as in this
            // case they would be cached by the Spring container but would not
            // have been weaved
            Class<?> beanType = this.beanFactory.getType(beanName);
            if (beanType == null) {
               continue;
            }
             //判断Bean是否是切面Bean,isAspect方法判断[标注1]
            if (this.advisorFactory.isAspect(beanType)) {
               aspectNames.add(beanName);
               AspectMetadata amd = new AspectMetadata(beanType, beanName);
               if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
                  MetadataAwareAspectInstanceFactory factory =
                        new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
                   //解析aop class的配置,包返回Advisor对象[标注2]
                  List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
                  if (this.beanFactory.isSingleton(beanName)) {
                     this.advisorsCache.put(beanName, classAdvisors);
                  }
                  else {
                     this.aspectFactoryCache.put(beanName, factory);
                  }
                  advisors.addAll(classAdvisors);
               }
               else {
                  // Per target or per this.
                  if (this.beanFactory.isSingleton(beanName)) {
                     throw new IllegalArgumentException("Bean with name '" + beanName +
                           "' is a singleton, but aspect instantiation model is not singleton");
                  }
                  MetadataAwareAspectInstanceFactory factory =
                        new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
                  this.aspectFactoryCache.put(beanName, factory);
                  advisors.addAll(this.advisorFactory.getAdvisors(factory));
               }
            }
         }
         this.aspectBeanNames = aspectNames;
         return advisors;
      }
   }
   if (aspectNames.isEmpty()) {
      return Collections.emptyList();
   }
   List<Advisor> advisors = new LinkedList<Advisor>();
   for (String aspectName : aspectNames) {
      List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
      if (cachedAdvisors != null) {
         advisors.addAll(cachedAdvisors);
      }
      else {
         MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
         advisors.addAll(this.advisorFactory.getAdvisors(factory));
      }
   }
   return advisors;
}

**[标注1]如何判断类是否是aop切面配置类? **

通过以下代码。

@Override
public boolean isAspect(Class<?> clazz) {
   return (hasAspectAnnotation(clazz) && !compiledByAjc(clazz));
}
private boolean hasAspectAnnotation(Class<?> clazz) {
    //包含@Aspect注解
   return (AnnotationUtils.findAnnotation(clazz, Aspect.class) != null);
}

[标注2]如何解析为Advisor对象?

ReflectiveAspectJAdvisorFactory#getAdvisors 遍历所有没被@PointCut注解标注的方法,也就是遍历切面内容方法

ReflectiveAspectJAdvisorFactory#getAdvisor 处理所有没被@PointCut注解标注的方法,候选切面内容方法

代码如下。

@Override
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
      int declarationOrderInAspect, String aspectName) {
   validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
   //解析判断候选方法是否有@Before,@After,@Around等注解,如果有,就继续执行新建Advisor对象。
   AspectJExpressionPointcut expressionPointcut = getPointcut(
         candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
   if (expressionPointcut == null) {
      return null;
   }
//创建advisor
   return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
         this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

最终循环解析,@Before,@After,@Around等标注的方法都会新建一个Advisor对象。新建的Advisor对象都保存在BeanFactoryAspectJAdvisorsBuilder#advisorsCache中,当AnnotationAwareAspectJAutoProxyCreator拦截bean的创建过程时,从这里面适配是否有切面可用。

这里解析得到的Advisor,大概有以下信息。下面的信息中,并没有对@PointCut注解做处理,pointCut属性只得出一个"mypoint()",此时还不知道Advisor实际对应的拦截表达式。

拦截表达式还是空的,会在AnnotationAwareAspectJAutoProxyCreator#postProcessAfterInstantiation第一次执行时解析拦截表达式。

适配切面

在AbstractAutoProxyCreator#postProcessAfterInitialization执行时,找到上面AbstractAutoProxyCreator#postProcessBeforeInitialization缓存的所有的切面信息,之后是如何进行切面适配,从而决定是否需要进行代理对象的创建呢?

在调用AbstractAutoProxyCreator#postProcessAfterInitialization方法时,进行切面适配,并且会根据适配创建代理对象。根据以下调用链。

AbstractAutoProxyCreator#postProcessAfterInitialization

AbstractAutoProxyCreator#wrapIfNecessary

protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   if (beanName != null && 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;
   }
   // Create proxy if we have advice.
    //查找匹配切面
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   if (specificInterceptors != DO_NOT_PROXY) {
      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;
}

AbstractAdvisorAutoProxyCreator#getAdvicesAndAdvisorsForBean

AbstractAdvisorAutoProxyCreator#findEligibleAdvisors

protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
    //从缓存取出所有切面信息
   List<Advisor> candidateAdvisors = findCandidateAdvisors();
    //根据advisor信息中的表达式进行方法对class的匹配
   List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
   extendAdvisors(eligibleAdvisors);
   if (!eligibleAdvisors.isEmpty()) {
      eligibleAdvisors = sortAdvisors(eligibleAdvisors);
   }
   return eligibleAdvisors;
}

此时如果是第一次执行适配方法findAdvisorsThatCanApply的话,candidateAdvisors中的拦截表达式还是空的,需要进行表达式获取,也就是@Pointcut的value。spring的操作的在第一次执行findAdvisorsThatCanApply时解析获取拦截表达式的值,获得拦截表达式值之后就跟当前class的方法进行匹配看是否需要进行代理。

继续往下跟踪代码

AopUtils#canApply(org.springframework.aop.Advisor, java.lang.Class<?>, boolean)

AopUtils#canApply(org.springframework.aop.Pointcut, java.lang.Class<?>, boolean)

AspectJExpressionPointcut#getClassFilter

AspectJExpressionPointcut#checkReadyToMatch

private void checkReadyToMatch() {
   if (getExpression() == null) {
      throw new IllegalStateException("Must set property 'expression' before attempting to match");
   }
   if (this.pointcutExpression == null) {
      this.pointcutClassLoader = (this.beanFactory instanceof ConfigurableBeanFactory ?
            ((ConfigurableBeanFactory) this.beanFactory).getBeanClassLoader() :
            ClassUtils.getDefaultClassLoader());
       //解析得到拦截表达式,例如根据@Before的value来关联查询出对应的表达式
      this.pointcutExpression = buildPointcutExpression(this.pointcutClassLoader);
   }
}

最终解析完之后,advisor中的表达式信息结构如下图。包含在pointcut属性中,匹配时就根据pointcutExpression循环进行匹配class的方法。有兴趣的可以继续调试看看是如何实现匹配表达式的。

##  创建代理对象

如果在上面的匹配切面过程中,发现适配的切面,那就需要进行代理对象的创建了。

我们回到上面的AbstractAutoProxyCreator#wrapIfNecessary,主要看代码如下。

  // Create proxy if we have advice.
    //查找匹配切面
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   if (specificInterceptors != DO_NOT_PROXY) {
      this.advisedBeans.put(cacheKey, Boolean.TRUE);
       //创建代理对象
      Object proxy = createProxy(
            bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
      this.proxyTypes.put(cacheKey, proxy.getClass());
      return proxy;
   }

所以,继续看

AbstractAutoProxyCreator#createProxy

的创建代理对象方法。设置ProxyFactory创建Proxy需要的一切信息。

protected Object createProxy(
      Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
   if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
      AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
   }
    //新建代理对象工厂
   ProxyFactory proxyFactory = new ProxyFactory();
   proxyFactory.copyFrom(this);
    //设置工厂代理类
   if (!proxyFactory.isProxyTargetClass()) {
      if (shouldProxyTargetClass(beanClass, beanName)) {
         proxyFactory.setProxyTargetClass(true);
      }
      else {
         evaluateProxyInterfaces(beanClass, proxyFactory);
      }
   }
    //设置拦截切面
   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
   for (Advisor advisor : advisors) {
      proxyFactory.addAdvisor(advisor);
   }
    //设置被代理对象
   proxyFactory.setTargetSource(targetSource);
   customizeProxyFactory(proxyFactory);
   proxyFactory.setFrozen(this.freezeProxy);
   if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
   }
//创建代理对象
   return proxyFactory.getProxy(getProxyClassLoader());
}

下面看ProxyFactory是如何创建代理对象,继续跟踪proxyFactory.getProxy(getProxyClassLoader());

public Object getProxy(ClassLoader classLoader) {
   return createAopProxy().getProxy(classLoader);
}

createAopProxy()作用是根据class的种类判断采用的代理方式,看如下实现

DefaultAopProxyFactory#createAopProxy

@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
	if (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)) {
            //采用jdk动态代理必须基于接口
			return new JdkDynamicAopProxy(config);
		}
        //基于cglib实现代理不需要接口
		return new ObjenesisCglibAopProxy(config);
	}
	else {
		return new JdkDynamicAopProxy(config);
	}
}

所以在当前调试的例子中,使用cglib代理。所以执行如下代理。

@Override
public Object getProxy(ClassLoader classLoader) {
     //。。。。。。
      // Configure CGLIB Enhancer...
      Enhancer enhancer = createEnhancer();
      if (classLoader != null) {
         enhancer.setClassLoader(classLoader);
         if (classLoader instanceof SmartClassLoader &&
               ((SmartClassLoader) classLoader).isClassReloadable(proxySuperClass)) {
            enhancer.setUseCache(false);
         }
      }
      enhancer.setSuperclass(proxySuperClass);
      enhancer.setInterfaces(AopProxyUtils.completeProxiedInterfaces(this.advised));
      enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
      enhancer.setStrategy(new ClassLoaderAwareUndeclaredThrowableStrategy(classLoader));
	//获取拦截回调函数
      Callback[] callbacks = getCallbacks(rootClass);
      Class<?>[] types = new Class<?>[callbacks.length];
      for (int x = 0; x < types.length; x++) {
         types[x] = callbacks[x].getClass();
      }
      // fixedInterceptorMap only populated at this point, after getCallbacks call above
      enhancer.setCallbackFilter(new ProxyCallbackFilter(
            this.advised.getConfigurationOnlyCopy(), this.fixedInterceptorMap, this.fixedInterceptorOffset));
      enhancer.setCallbackTypes(types);
      // Generate the proxy class and create a proxy instance.
    //返回一个cglib代理对象
      return createProxyClassAndInstance(enhancer, callbacks);
   }
   catch (CodeGenerationException ex) {
       //、、、、、、
   }
}

getCallbacks(rootClass);在这个获取回调函数的方法中,普通的aop采用的回调函数是如下的方式。

// Choose an "aop" interceptor (used for AOP calls).
Callback aopInterceptor = new DynamicAdvisedInterceptor(this.advised);

cglib 的aop回调函数如下。

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
   Object oldProxy = null;
   boolean setProxyContext = false;
   Class<?> targetClass = null;
   Object target = null;
   try {
       //这里注入的advised就是之前创建的ProxyFactory对象
      if (this.advised.exposeProxy) {
         // Make invocation available if necessary.
         oldProxy = AopContext.setCurrentProxy(proxy);
         setProxyContext = true;
      }
      // May be null. Get as late as possible to minimize the time we
      // "own" the target, in case it comes from a pool...
      target = getTarget();
      if (target != null) {
         targetClass = target.getClass();
      }
       //根据切面信息创建切面内容调用链
      List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
      Object retVal;
      // Check whether we only have one InvokerInterceptor: that is,
      // no real advice, but just reflective invocation of the target.
      if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
         // We can skip creating a MethodInvocation: just invoke the target directly.
         // Note that the final invoker must be an InvokerInterceptor, so we know
         // it does nothing but a reflective operation on the target, and no hot
         // swapping or fancy proxying.
         Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
         retVal = methodProxy.invoke(target, argsToUse);
      }
      else {
         // We need to create a method invocation...
          //创建一个方法调用对象,具体调用实现没分析,Before逻辑大概是先调用切面,在反射调用目标方法
         retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
      }
      retVal = processReturnType(proxy, target, method, retVal);
      return retVal;
   }
   finally {
      if (target != null) {
         releaseTarget(target);
      }
      if (setProxyContext) {
         // Restore old proxy.
         AopContext.setCurrentProxy(oldProxy);
      }
   }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • spring aop底层原理及如何实现

    前言 相信每天工作都要用spring框架的大家一定使用过spring aop,aop的概念是面向切面编程,相对与传统的面向对象编程oop,aop更关注的是横向的逻辑,比如说一个大型系统中的日志记录,异常处理,性能监控等等,都是各个模块都需要的操作,那样代表着这些操作会散落在系统的各个地方,不易管理且杂乱无章,而aop就是关注的这些,aop将这些操作与业务代码分离,统一成一个个的切面,针对这些个切面进行编程处理.spring aop使得我们的aop开发工作变得简单,这次我就给大家讲讲spring

  • Spring Bean生命周期源码原理图解

    概述 spring流行了很长时间了,是一个用java编写的轻量级框架,受到了很多公司及程序员的欢迎,Bean生命周期是一个对象从实例化开始到销毁的全过程,了解生命周期是很有必要的. 重要性 spring的生命周期是比较复杂的,只有了解其过程及原理才能更好的扩展程序. 源码剖析生命周期过程bean的实例化 属性填充及Aware接口检测设置依赖 如果容器自定义了BeanpostProcessor的实现类,则执行处理器相应的前置处理 bean实现了初始化接口InitlializingBean,则会执行

  • Spring AOP实现Redis缓存数据库查询源码

    应用场景 我们希望能够将数据库查询结果缓存到Redis中,这样在第二次做同样的查询时便可以直接从redis取结果,从而减少数据库读写次数. 需要解决的问题 操作缓存的代码写在哪?必须要做到与业务逻辑代码完全分离. 如何避免脏读? 从缓存中读出的数据必须与数据库中的数据一致. 如何为一个数据库查询结果生成一个唯一的标识?即通过该标识(Redis中为Key),能唯一确定一个查询结果,同一个查询结果,一定能映射到同一个key.只有这样才能保证缓存内容的正确性 如何序列化查询结果?查询结果可能是单个实体

  • Spring AOP底层源码详解

    ProxyFactory的工作原理 ProxyFactory是一个代理对象生产工厂,在生成代理对象之前需要对代理工厂进行配置.ProxyFactory在生成代理对象之前需要决定到底是使用JDK动态代理还是CGLIB技术. // config就是ProxyFactory对象 // optimize为true,或proxyTargetClass为true,或用户没有给ProxyFactory对象添加interface if (config.isOptimize() || config.isProxy

  • spring源码阅读--aop实现原理讲解

    目录 aop实现原理简介 代理实现的处理器(BeanPostProcessor) 代理实现的源头–AnnotationAwareAspectJAutoProxyCreator AnnotationAwareAspectJAutoProxyCreator的继承结构 代理对象(Proxy)的创建 解析并缓存切面 适配切面 aop实现原理简介 首先我们都知道aop的基本原理就是动态代理思想,在设计模式之代理模式中有介绍过这两种动态代理的使用与基本原理,再次不再叙述. 这里分析的是,在spring中是如

  • spring源码阅读--@Transactional实现原理讲解

    目录 @Transactional注解简介 spring中声明式事务实现原理猜想 @Transactional作用 动态代理逻辑实现 TransactionInterceptor–最终事务管理者 总结 @Transactional注解简介 @Transactional是spring中声明式事务管理的注解配置方式,相信这个注解的作用大家都很清楚. @Transactional注解可以帮助我们把事务开启.提交或者回滚的操作,通过aop的方式进行管理. 通过@Transactional注解就能让spr

  • 教你使用IDEA搭建spring源码阅读环境的详细步骤

    目录 第一步.准备gradle环境 第二步.下载spring源码 第一步.准备gradle环境 1.去官网下载gradle https://gradle.org/releases/ 2.将其解压缩,创建repository文件夹 和init.d文件夹 创建init.gradle文件 输入文本信息,主要是配置阿里云镜像仓库地址,和maven的类似 gradle.projectsLoaded { rootProject.allprojects { buildscript { repositories

  • 基于Gradle搭建Spring 5.3.13-release源码阅读环境的详细流程

    目录 # 1.安装JDK # 2.安装Gradle # 3.Spring版本命名规则 # 4.下载Spring 5.3.13-release源码 # 5.修改Spring源码中Gradle配置 # 6.构建Spring源码 # 7.导入IDEA 点击File --> New --> Project from Existing Sources... # 8.创建Spring源码debug调试模块 # 基于Gradle搭建Spring 5.5.13-release源码阅读环境 Spring版本:5

  • grade构建阅读spring源码环境 Idea2020.3的过程

    笔者看了很多博客,从早上搞到晚上,终于成功了

  • springboot-2.3.x最新版源码阅读环境搭建(基于gradle构建)

    一.前言 跟很多小伙伴聊天,发现一个严重的问题,很多小伙伴横向发展的貌似很不错,很多技术都能说出一二,但是如果在某个技术上深挖一下就不行了,问啥啥不会.就拿springboot来说,很多同学止步于springboot的应用,再往深处就一问三不知了,那么如何破局呢?smart哥认为最好的办法就是直捣黄龙,要把一个技术理解透了,听别人讲一万遍原理,不如自己撕一遍源码. 要阅读源码那就首先得先搭建源码阅读环境,那么本篇文章就来介绍下Spring Boot的源码环境搭建. 鉴于spring团队已经全面抛

  • spring源码学习之bean的初始化以及循环引用

    实例化方法,把bean实例化,并且包装成BeanWrapper 1.点进这个方法里面. 这个方法是反射调用类中的 factoryMethod 方法. 这要知道@Bean 方法的原理, 实际上spring 会扫描有@bean 注解的方法, 然后把方法名称设置到 BeanDefinition 的 factoryMethod属性中, 接下来就会调到上面截图中的方法实现@Bean 方法的调用. 2. 有参构造函数的时候 determineConstructorsFromBeanPostProcessor

  • Spring源码解析之编程式事务

    一.前言 在Spring中,事务有两种实现方式: 编程式事务管理: 编程式事务管理使用TransactionTemplate可实现更细粒度的事务控制.声明式事务管理: 基于Spring AOP实现.其本质是对方法前后进行拦截,然后在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务. 声明式事务管理不需要入侵代码,通过@Transactional就可以进行事务操作,更快捷而且简单(尤其是配合spring boot自动配置,可以说是精简至极!),且大部分业务都可

  • Three.js源码阅读笔记(物体是如何组织的)

    这是Three.js源码阅读笔记第三篇.之前两篇主要是关于核心对象的,这些核心对象主要围绕着矢量vector3对象和矩阵matrix4对象展开的,关注的是空间中的单个顶点的位置和变化.这一篇将主要讨论Three.js中的物体是如何组织的:即如何将顶点.表面.材质组合成为一个具体的对象. Object::Mesh 该构造函数构造了一个空间中的物体.之所以叫"网格"是因为,实际上具有体积的物体基本都是建模成为"网格"的. 复制代码 代码如下: THREE.Mesh =

  • Idea 搭建Spring源码环境的超详细教程

    本篇主要讲解如何使用Ideal 搭建Spring的源码环境,想必大家都会多多少少去看过Spring的部分源码,一般我们都是直接点进某个Spring类 然后Idea上面去下载 ,但是确实比较麻烦,而且不能添加自己对源码的注释 理解 ,本篇就来解决这个问题,手把手使用Idea 搭建Spring framework ,并且直接在Spring framework项目中添加我们自己的module 来验证环境是否正确. 本过程会比较耗时 而且容易出错 慢慢来吧. 1. clone spring-framew

随机推荐