AOP源码解析之二-创建AOP代理前传,获取AOP信息。

上篇文章对AOP的基本概念说清楚了,那么接下来的AOP还剩下两个大的步骤获取定义的AOP信息,生成代理对象扔到beanFactory中。

本篇文章重点对前半部分,如何获取到AOP信息的过程解读。

在Spring的核心方法Refresh方法中,aop是在

  1. Object bean = resolveBeforeInstantiation(beanName, mbdToUse);

开始切入的,该文章就开始深入这个方法进行解析。

  1. @Nullable
  2. protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
  3. Object bean = null;
  4. // 检测是否被解析过
  5. if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
  6. // Make sure bean class is actually resolved at this point.
  7. // hasInstantiationAwareBeanPostProcessors()是来判断容器中是否有InstantiationAwareBeanPostProcessor的实现bean
  8. // AOP切面后置处理器AspectJAwareAdvisorAutoProxyCreator就实现了InstantiationAwareBeanPostProcessor接口
  9. if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
  10. Class<?> targetType = determineTargetType(beanName, mbd);
  11. if (targetType != null) {
  12. // 执行实现了InstantiationAwareBeanPostProcessor接口的BeanPostProcessor中的前置处理方法postProcessBeforeInstantiation方法
  13. bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
  14. if (bean != null) {
  15. // 执行实现了InstantiationAwareBeanPostProcessor接口的BeanPostProcessor中的后置处理方法postProcessAfterInitialization方法
  16. bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
  17. }
  18. }
  19. }
  20. mbd.beforeInstantiationResolved = (bean != null);
  21. }
  22. return bean;
  23. }

见名知意,resolveBeforeInstantiation(执行初始化前方法),这一步主要判断一下工厂中是否有 InstantiationAwareBeanPostProcessor 的实现bean。InstantiationAwareBeanPostProcessor 应该是AOP最核心的接口了。

我们看一下InstantiationAwareBeanPostProcessor 的继承结构。

我们详细的说下InstantiationAwareBeanPostProcessor 这个接口。

  1. public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {
  2. Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException;
  3. boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException;
  4. PropertyValues postProcessPropertyValues(
  5. PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException;
  6. }

它和 BeanPostProcessor 的方法非常相似,而且它还继承了 BeanPostProcessor。

下面是 BeanPostProcessor 中的两个方法:

  1. Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
  2. Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;

发现没有,InstantiationAwareBeanPostProcessor 是 Instantiation,BeanPostProcessor 是 Initialization,它代表的是 bean 在实例化完成并且属性注入完成,在执行 init-method 的前后进行作用的。

而 InstantiationAwareBeanPostProcessor 的执行时机要前面一些,我们回到refresh方法的doCreateBean中看一下。

看到这读者想必对于aop的执行时机已经模模糊糊的心里有个大概了。

我们定义的环绕通知,创建代理一定是在postProcessBeforeInitialization完成的。

我们的重点就是看看postProcessBeforeInitialization的方法中的通知怎么获取,怎么创建代理对象的进行详细的解读。

本文先对前半部分解读。

我们继续看postProcessBeforeInitialization有哪些实现类。

我们重点看AbstractAutoProxyCreator的实现类。

  1. @Override
  2. public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
  3. if (bean != null) {
  4. Object cacheKey = getCacheKey(bean.getClass(), beanName);
  5. // 1.判断当前bean是否需要被代理,如果需要则进行封装
  6. if (this.earlyProxyReferences.remove(cacheKey) != bean) {
  7. //1.判断当前bean是否需要被代理,如果需要则进行封装
  8. return wrapIfNecessary(bean, beanName, cacheKey);
  9. }
  10. }
  11. return bean;
  12. }

如果需要代理执行继wrapIfNecessary方法。

  1. //这个方法将返回代理类
  2. protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
  3. // 1.判断当前bean是否在targetSourcedBeans缓存中存在(已经处理过),如果存在,则直接返回当前bean
  4. if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
  5. return bean;
  6. }
  7. // 2.在advisedBeans缓存中存在,并且value为false,则代表无需处理
  8. if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
  9. return bean;
  10. }
  11. // 3.bean的类是aop基础设施类 || bean应该跳过,则标记为无需处理,并返回
  12. if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
  13. this.advisedBeans.put(cacheKey, Boolean.FALSE);
  14. return bean;
  15. }
  16. // Create proxy if we have advice.
  17. // 4.获取当前bean的Advices和Advisors
  18. Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
  19. // 5.如果存在增强器则创建代理
  20. if (specificInterceptors != DO_NOT_PROXY) {
  21. this.advisedBeans.put(cacheKey, Boolean.TRUE);
  22. // 创建代理...创建代理...创建代理...
  23. // 5.1 创建代理对象:这边SingletonTargetSource的target属性存放的就是我们原来的bean实例(也就是被代理对象),
  24. // 用于最后增加逻辑执行完毕后,通过反射执行我们真正的方法时使用(method.invoke(bean, args))
  25. Object proxy = createProxy(
  26. bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
  27. // 5.2 创建完代理后,将cacheKey -> 代理类的class放到缓存
  28. this.proxyTypes.put(cacheKey, proxy.getClass());
  29. return proxy;
  30. }
  31. // 6.标记为无需处理
  32. this.advisedBeans.put(cacheKey, Boolean.FALSE);
  33. return bean;
  34. }

4.1 我们先查看第一条主线,获取当前bean的Advices和Advisors

  1. @Override
  2. @Nullable
  3. protected Object[] getAdvicesAndAdvisorsForBean(
  4. Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {
  5. // 1.找到符合条件的Advisor
  6. List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
  7. if (advisors.isEmpty()) {
  8. // 2.如果没有符合条件的Advisor,则返回null
  9. return DO_NOT_PROXY;
  10. }
  11. return advisors.toArray();
  12. }

注:Advisors即是aop的环绕通知。

  1. protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
  2. // 1.查找所有的候选Advisor
  3. List<Advisor> candidateAdvisors = findCandidateAdvisors();
  4. // 2.从所有候选的Advisor中找出符合条件的
  5. List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
  6. // 3.扩展方法,留个子类实现
  7. extendAdvisors(eligibleAdvisors);
  8. if (!eligibleAdvisors.isEmpty()) {
  9. // 4.对符合条件的Advisor进行排序
  10. eligibleAdvisors = sortAdvisors(eligibleAdvisors);
  11. }
  12. return eligibleAdvisors;
  13. }

这一步所做的事很简单,就是查找所有候选的Advisor,但是调用链路特别的长,如果将这些彻底搞明白,还是需要耗费一番功夫的,读者可以选择深入程度。

1、寻找可用的Advisor

  1. public List<Advisor> findAdvisorBeans() {
  2. // Determine list of advisor bean names, if not cached already.
  3. // 1.确认advisor的beanName列表,优先从缓存中拿
  4. String[] advisorNames = this.cachedAdvisorBeanNames;
  5. if (advisorNames == null) {
  6. // Do not initialize FactoryBeans here: We need to leave all regular beans
  7. // uninitialized to let the auto-proxy creator apply to them!
  8. // 1.1 如果缓存为空,则获取class类型为Advisor的所有bean名称
  9. advisorNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
  10. this.beanFactory, Advisor.class, true, false);
  11. this.cachedAdvisorBeanNames = advisorNames;
  12. }
  13. if (advisorNames.length == 0) {
  14. return new ArrayList<>();
  15. }
  16. // 2.遍历处理advisorNames
  17. List<Advisor> advisors = new ArrayList<>();
  18. for (String name : advisorNames) {
  19. if (isEligibleBean(name)) {
  20. // 2.1 跳过当前正在创建的advisor
  21. if (this.beanFactory.isCurrentlyInCreation(name)) {
  22. if (logger.isTraceEnabled()) {
  23. logger.trace("Skipping currently created advisor '" + name + "'");
  24. }
  25. }
  26. else {
  27. try {
  28. // 2.2 通过beanName获取对应的bean对象,并添加到advisors
  29. advisors.add(this.beanFactory.getBean(name, Advisor.class));
  30. }
  31. catch (BeanCreationException ex) {
  32. Throwable rootCause = ex.getMostSpecificCause();
  33. if (rootCause instanceof BeanCurrentlyInCreationException) {
  34. BeanCreationException bce = (BeanCreationException) rootCause;
  35. String bceBeanName = bce.getBeanName();
  36. if (bceBeanName != null && this.beanFactory.isCurrentlyInCreation(bceBeanName)) {
  37. if (logger.isTraceEnabled()) {
  38. logger.trace("Skipping advisor '" + name +
  39. "' with dependency on currently created bean: " + ex.getMessage());
  40. }
  41. // Ignore: indicates a reference back to the bean we're trying to advise.
  42. // We want to find advisors other than the currently created bean itself.
  43. continue;
  44. }
  45. }
  46. throw ex;
  47. }
  48. }
  49. }
  50. }
  51. // 3.返回符合条件的advisor列表
  52. return advisors;
  53. }
  1. /**
  2. * 找到符合条件的Advisor
  3. * @return
  4. */
  5. @Override
  6. protected List<Advisor> findCandidateAdvisors() {
  7. // Add all the Spring advisors found according to superclass rules.
  8. List<Advisor> advisors = super.findCandidateAdvisors();
  9. // Build Advisors for all AspectJ aspects in the bean factory.
  10. if (this.aspectJAdvisorsBuilder != null) {
  11. advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
  12. }
  13. return advisors;
  14. }
  1. public List<Advisor> buildAspectJAdvisors() {
  2. List<String> aspectNames = this.aspectBeanNames;
  3. // 1.如果aspectNames为空,则进行解析
  4. if (aspectNames == null) {
  5. synchronized (this) {
  6. aspectNames = this.aspectBeanNames;
  7. if (aspectNames == null) {
  8. List<Advisor> advisors = new ArrayList<>();
  9. aspectNames = new ArrayList<>();
  10. // 1.1 获取所有的beanName
  11. String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
  12. this.beanFactory, Object.class, true, false);
  13. // 1.2 循环遍历所有的beanName,找出对应的增强方法
  14. for (String beanName : beanNames) {
  15. // 1.3 不合法的beanName则跳过,默认返回true,子类可以覆盖实现,AnnotationAwareAspectJAutoProxyCreator
  16. // 实现了自己的逻辑,支持使用includePatterns进行筛选
  17. if (!isEligibleBean(beanName)) {
  18. continue;
  19. }
  20. // We must be careful not to instantiate beans eagerly as in this case they
  21. // would be cached by the Spring container but would not have been weaved.
  22. // 获取beanName对应的bean的类型
  23. Class<?> beanType = this.beanFactory.getType(beanName);
  24. if (beanType == null) {
  25. continue;
  26. }
  27. // 1.4 如果beanType存在Aspect注解则进行处理
  28. if (this.advisorFactory.isAspect(beanType)) {
  29. // 将存在Aspect注解的beanName添加到aspectNames列表
  30. aspectNames.add(beanName);
  31. // 新建切面元数据
  32. AspectMetadata amd = new AspectMetadata(beanType, beanName);
  33. if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
  34. // 使用BeanFactory和beanName创建一个BeanFactoryAspectInstanceFactory,主要用来创建切面对象实例
  35. MetadataAwareAspectInstanceFactory factory =
  36. new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
  37. // 1.5 解析标记AspectJ注解中的增强方法*********************
  38. List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
  39. // 1.6 放到缓存中
  40. if (this.beanFactory.isSingleton(beanName)) {
  41. // 如果beanName是单例则直接将解析的增强方法放到缓存
  42. this.advisorsCache.put(beanName, classAdvisors);
  43. }
  44. else {
  45. // 如果不是单例,则将factory放到缓存,之后可以通过factory来解析增强方法
  46. this.aspectFactoryCache.put(beanName, factory);
  47. }
  48. // 1.7 将解析的增强器添加到advisors
  49. advisors.addAll(classAdvisors);
  50. }
  51. else {
  52. // Per target or per this.
  53. if (this.beanFactory.isSingleton(beanName)) {
  54. // 名称为beanName的Bean是单例,但切面实例化模型不是单例,则抛异常
  55. throw new IllegalArgumentException("Bean with name '" + beanName +
  56. "' is a singleton, but aspect instantiation model is not singleton");
  57. }
  58. MetadataAwareAspectInstanceFactory factory =
  59. new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
  60. // 将factory放到缓存,之后可以通过factory来解析增强方法
  61. this.aspectFactoryCache.put(beanName, factory);
  62. // 解析标记AspectJ注解中的增强方法,并添加到advisors中
  63. advisors.addAll(this.advisorFactory.getAdvisors(factory));
  64. }
  65. }
  66. }
  67. // 1.9 将解析出来的切面beanName放到缓存aspectBeanNames
  68. this.aspectBeanNames = aspectNames;
  69. return advisors;
  70. }
  71. }
  72. }
  73. if (aspectNames.isEmpty()) {
  74. return Collections.emptyList();
  75. }
  76. List<Advisor> advisors = new ArrayList<>();
  77. for (String aspectName : aspectNames) {
  78. List<Advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
  79. if (cachedAdvisors != null) {
  80. advisors.addAll(cachedAdvisors);
  81. }
  82. else {
  83. MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
  84. advisors.addAll(this.advisorFactory.getAdvisors(factory));
  85. }
  86. }
  87. // 1.10 最后返回解析出来的增强器
  88. return advisors;
  89. }
  1. @Override
  2. public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
  3. // 1.前面我们将beanClass和beanName封装成了aspectInstanceFactory的AspectMetadata属性,
  4. // 这边可以通过AspectMetadata属性重新获取到当前处理的切面类
  5. Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
  6. // 2.获取当前处理的切面类的名字
  7. String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
  8. // 3.校验切面类
  9. validate(aspectClass);
  10. // We need to wrap the MetadataAwareAspectInstanceFactory with a decorator
  11. // so that it will only instantiate once.
  12. // 4.使用装饰器包装MetadataAwareAspectInstanceFactory,以便它只实例化一次。
  13. MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
  14. new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
  15. List<Advisor> advisors = new ArrayList<>();
  16. // 5.获取切面类中的方法(也就是我们用来进行逻辑增强的方法,被@Around、@After等注解修饰的方法,使用@Pointcut的方法不处理)
  17. for (Method method : getAdvisorMethods(aspectClass)) {
  18. // 6.处理method,获取增强器
  19. Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, advisors.size(), aspectName);
  20. if (advisor != null) {
  21. // 7.如果增强器不为空,则添加到advisors
  22. advisors.add(advisor);
  23. }
  24. }
  25. // If it's a per target aspect, emit the dummy instantiating aspect.
  26. if (!advisors.isEmpty() && lazySingletonAspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
  27. // 8.如果寻找的增强器不为空而且又配置了增强延迟初始化,那么需要在首位加入同步实例化增强器(用以保证增强使用之前的实例化)
  28. Advisor instantiationAdvisor = new SyntheticInstantiationAdvisor(lazySingletonAspectInstanceFactory);
  29. advisors.add(0, instantiationAdvisor);
  30. }
  31. // Find introduction fields.
  32. // 9.获取DeclareParents注解
  33. for (Field field : aspectClass.getDeclaredFields()) {
  34. Advisor advisor = getDeclareParentsAdvisor(field);
  35. if (advisor != null) {
  36. advisors.add(advisor);
  37. }
  38. }
  39. return advisors;
  40. }
  1. @Override
  2. @Nullable
  3. public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
  4. int declarationOrderInAspect, String aspectName) {
  5. // 1.校验切面类
  6. validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
  7. // 2.AspectJ切点信息的获取(例如:表达式),就是指定注解的表达式信息的获取,
  8. // 如:@Around("execution(* com.joonwhee.open.aop.*.*(..))")
  9. AspectJExpressionPointcut expressionPointcut = getPointcut(
  10. candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
  11. // 3.如果expressionPointcut为null,则直接返回null
  12. if (expressionPointcut == null) {
  13. return null;
  14. }
  15. // 4.根据切点信息生成增强器
  16. return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
  17. this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
  18. }

获取到@Before, @Around, @After, @AfterReturning, @AfterThrowing, @Pointcut定义注解信息

  1. @Nullable
  2. private AspectJExpressionPointcut getPointcut(Method candidateAdviceMethod, Class<?> candidateAspectClass) {
  3. // 1.查找并返回给定方法的第一个AspectJ注解(@Before, @Around, @After, @AfterReturning, @AfterThrowing, @Pointcut)
  4. // 因为我们之前把@Pointcut注解的方法跳过了,所以这边必然不会获取到@Pointcut注解
  5. AspectJAnnotation<?> aspectJAnnotation =
  6. AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(candidateAdviceMethod);
  7. // 2.如果方法没有使用AspectJ的注解,则返回null
  8. if (aspectJAnnotation == null) {
  9. return null;
  10. }
  11. // 3.使用AspectJExpressionPointcut实例封装获取的信息
  12. AspectJExpressionPointcut ajexp =
  13. new AspectJExpressionPointcut(candidateAspectClass, new String[0], new Class<?>[0]);
  14. // 提取得到的注解中的表达式,
  15. // 例如:@Around("execution(* com.joonwhee.open.aop.*.*(..))"),得到:execution(* com.joonwhee.open.aop.*.*(..))
  16. ajexp.setExpression(aspectJAnnotation.getPointcutExpression());
  17. if (this.beanFactory != null) {
  18. ajexp.setBeanFactory(this.beanFactory);
  19. }
  20. return ajexp;
  21. }
  1. @Nullable
  2. protected static AspectJAnnotation<?> findAspectJAnnotationOnMethod(Method method) {
  3. // 设置要查找的注解类
  4. for (Class<?> clazz : ASPECTJ_ANNOTATION_CLASSES) {
  5. // 查找方法上是否存在当前遍历的注解,如果有则返回
  6. AspectJAnnotation<?> foundAnnotation = findAnnotation(method, (Class<Annotation>) clazz);
  7. if (foundAnnotation != null) {
  8. return foundAnnotation;
  9. }
  10. }
  11. return null;
  12. }

2、获取切点以后就需要生成增强器了。

  1. new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
  2. this, aspectInstanceFactory, declarationOrderInAspect, aspectName)
  1. /**
  2. * 根据切点信息生成增强器
  3. * @param declaredPointcut
  4. * @param aspectJAdviceMethod
  5. * @param aspectJAdvisorFactory
  6. * @param aspectInstanceFactory
  7. * @param declarationOrder
  8. * @param aspectName
  9. */
  10. public InstantiationModelAwarePointcutAdvisorImpl(AspectJExpressionPointcut declaredPointcut,
  11. Method aspectJAdviceMethod, AspectJAdvisorFactory aspectJAdvisorFactory,
  12. MetadataAwareAspectInstanceFactory aspectInstanceFactory, int declarationOrder, String aspectName) {
  13. // 1.简单的将信息封装在类的实例中
  14. this.declaredPointcut = declaredPointcut;
  15. this.declaringClass = aspectJAdviceMethod.getDeclaringClass();
  16. this.methodName = aspectJAdviceMethod.getName();
  17. this.parameterTypes = aspectJAdviceMethod.getParameterTypes();
  18. // aspectJAdviceMethod保存的是我们用来进行逻辑增强的方法(@Around、@After等修饰的方法)
  19. this.aspectJAdviceMethod = aspectJAdviceMethod;
  20. this.aspectJAdvisorFactory = aspectJAdvisorFactory;
  21. this.aspectInstanceFactory = aspectInstanceFactory;
  22. this.declarationOrder = declarationOrder;
  23. this.aspectName = aspectName;
  24. // 2.是否需要延迟实例化
  25. if (aspectInstanceFactory.getAspectMetadata().isLazilyInstantiated()) {
  26. // Static part of the pointcut is a lazy type.
  27. Pointcut preInstantiationPointcut = Pointcuts.union(
  28. aspectInstanceFactory.getAspectMetadata().getPerClausePointcut(), this.declaredPointcut);
  29. // Make it dynamic: must mutate from pre-instantiation to post-instantiation state.
  30. // If it's not a dynamic pointcut, it may be optimized out
  31. // by the Spring AOP infrastructure after the first evaluation.
  32. this.pointcut = new PerTargetInstantiationModelPointcut(
  33. this.declaredPointcut, preInstantiationPointcut, aspectInstanceFactory);
  34. this.lazy = true;
  35. }
  36. else {
  37. // A singleton aspect.
  38. this.pointcut = this.declaredPointcut;
  39. this.lazy = false;
  40. // 3.实例化增强器:根据注解中的信息初始化对应的增强器
  41. this.instantiatedAdvice = instantiateAdvice(this.declaredPointcut);
  42. }
  43. }

经过以上长长的源码分析过程,就将aop的第一个大过程,获取到我们定义的@Before、@After的方法以后,进行增强,下一步就要拿到这些获取的信息去创建代理对象了。

AOP源码解析之二-创建AOP代理前传,获取AOP信息的更多相关文章

  1. 老生常谈系列之Aop--Spring Aop源码解析(二)

    老生常谈系列之Aop--Spring Aop源码解析(二) 前言 上一篇文章老生常谈系列之Aop--Spring Aop源码解析(一)已经介绍完Spring Aop获取advice切面增强方法的逻辑, ...

  2. 老生常谈系列之Aop--Spring Aop源码解析(一)

    老生常谈系列之Aop--Spring Aop源码解析(一) 前言 上一篇文章老生常谈系列之Aop--Spring Aop原理浅析大概阐述了动态代理的相关知识,并且最后的图给了一个Spring Aop实 ...

  3. 【Spring源码分析】AOP源码解析(上篇)

    前言 前面写了六篇文章详细地分析了Spring Bean加载流程,这部分完了之后就要进入一个比较困难的部分了,就是AOP的实现原理分析.为了探究AOP实现原理,首先定义几个类,一个Dao接口: pub ...

  4. AOP源码解析:AspectJAwareAdvisorAutoProxyCreator类的介绍

    AspectJAwareAdvisorAutoProxyCreator 的类图 上图中一些 类/接口 的介绍: AspectJAwareAdvisorAutoProxyCreator : 公开了Asp ...

  5. Spring事务源码解析(二)获取增强

    在上一篇文章@EnableTransactionManagement注解解析中,我们搭建了源码阅读的环境,以及解析了开启Spring事务功能的注解@EnableTransactionManagemen ...

  6. QT源码解析(一) QT创建窗口程序、消息循环和WinMain函数

    QT源码解析(一) QT创建窗口程序.消息循环和WinMain函数 分类: QT2009-10-28 13:33 17695人阅读 评论(13) 收藏 举报 qtapplicationwindowse ...

  7. # Volley源码解析(二) 没有缓存的情况下直接走网络请求源码分析#

    Volley源码解析(二) 没有缓存的情况下直接走网络请求源码分析 Volley源码一共40多个类和接口.除去一些工具类的实现,核心代码只有20多个类.所以相对来说分析起来没有那么吃力.但是要想分析透 ...

  8. Netty 源码解析(二):Netty 的 Channel

    本文首发于微信公众号[猿灯塔],转载引用请说明出处 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty源码解析(一):开始 当前:Netty 源码解析(二): Netty 的 Channel ...

  9. Cwinux源码解析(二)

    我在我的个人博客上发表了第二篇解析文章.欢迎各位读者批评指正. Cwinux源码解析(二)

随机推荐

  1. iOS 动画系列之动画解释

    动画解释 译文 http://blog.jobbole.com/69111/ 原文 http://www.objc.io/issues/12-animations/animations-explain ...

  2. SpringBoot+Dubbo+ZooKeeper+Maven入门实践

    原创:转载需注明原创地址 https://www.cnblogs.com/fanerwei222/p/11798626.html 注*** 本实例为仅适合初学者,关于dubbo和springboot以 ...

  3. 【struts2】中method={1}详解

    我们在使用struts2的时候,有时候为了简化struts2的配置项而采用通配符的方式,如下代码: <action name="ajaxregister!*" class=& ...

  4. 【C++】近期C++特性进阶学习总结(一)

    前言 C++的特性多的数不胜数,语言标准也很多,所以不定期对近期所学的C++知识进行总结,是对自身知识体系检查的良好机会,顺便锻炼一下写博客的文笔 三/五/零之法则 三之法则:如果某个类需要用户定义的 ...

  5. matlab构建栅格地图绘图思路

    matlab构建栅格地图绘图思路 近来因研究需要,调研并思考了栅格地图的生成方法,暂时总结以备不时之需. 栅格的建立最需要注意栅格粒度的问题,即根据需要调整栅格的边长,目前有两种思路一种是固定栅格边长 ...

  6. JavaWeb中jsp路径斜杆(/)跟没斜杆的路径映射问题

    在JavaWeb开发中,只要是写URL地址,那么建议最好以"/"开头,也就是使用绝对路径的方式,那么这个"/"到底代表什么呢?可以用如下的方式来记忆" ...

  7. Solution Set -「LOCAL」冲刺省选 Round XXIV

    \(\mathscr{Summary}\)   名副其实的 trash round,希望以后没有了.   A 题算好,确实一个比较关键的简化状态的点没想到,所以只拿了暴力(不考虑 \(\mathcal ...

  8. unity3d导出xcode项目使用afnetworking 3框架导致_kUTTagClassMIMEType 问题解决方案

    http://blog.csdn.net/huayu_huayu/article/details/51781953  (参考链接) Undefined symbols for architecture ...

  9. Paxos 学习笔记2 - Multi-Paxos

    Paxos 学习笔记2 - Multi-Paxos 图片来自 John Ousterhout 的 Raft user study 系列课程 Multi-Paxos 论文里对很多问题并没有描述清楚,所以 ...

  10. ASPack壳脱壳实验

    实验目的 1.学会使用相关软件工具,手动脱ASPack壳. 2.不要用PEiD查入口,单步跟踪,提高手动找入口能力. 实验内容 手动对文件"ASPack 2.12 - Alexey Solo ...