Spring源码分析

Spring源码分析

Spring使用流程(此处以xml配置为例)

  1. xml配置bean

  2. Application ac = new ClassPathXmlAppliation(“applicationContext.xml”);
    XXX xxx = ac.getBean(XXX.class);
    xxx.method;
    
  3. 加载xml -> 解析xml -> 封装BeanDefinition -> 实例化 -> 初始化 -> 放到容器 -> 从容器中获取

    xml四种解析方式:

    1. DOM解析
    2. SAX解析
    3. JDOM解析
    4. DOM4J解析
  4. 容器Map

    String Object
    Class Object
    String ObjectFactory
    String BeanDefinition
    

Bean的生命周期【不含销毁阶段】

一、Bean的定义

方式

xml\properties\yaml\json...无论何种形式只要实现BeanDefinitionReader规范(接口)进行解析为BeanDefinition对象

作用域

  • singleton:单例(默认)
  • prototype:每次需要时创建新的实例

以下仅适用于WebApplicationContext环境

  • request:每次HTTP请求都会创建一个新的Bean
  • session:同一个HTTP Session共享一个Bean,不同Session使用不同的Bean
  • global session:在一个全局的HTTP Session中,一个bean定义对应一个实例(仅在基于portlet的web应用中才有意义)

二、BeanDefinition实例化

在堆中开辟一块空间,对象的属性值都是默认值

实例化方式

反射

为什么是反射:灵活,可以获取Bean对象中所有方法属性注解以及一系列东西

反射获取Class对象的三种方式
  1. Class.forName("完全限定名");
    
  2. 对象.getClass();
    
  3. 类名.class;
    

BeanFactory(Bean工场)

整个容器的根接口,也是容器的接口,这里也能看到反射相关代码

常用实现工厂DefaultListabelBeanFactory

记住以下几个关键的:BeanFactory、 AbstractAutowiredCapableBeanFactory、 DefaultListableBeanFactory

在容器创建的过程中需要动态的改变bean的信息怎么处理?

PostProcessor 后置处理器(增强器)

  • BeanFactoryPostProcessor:增强BeanDefinition信息
  • BeanPostProcessor:增强Bean信息

实现BeanFactoryPostProcessor,可以自己设置一些属性:如懒加载、单例模式等

实际应用

例:PlaceholderConfigurerSupport

PlaceholderConfigurerSupport类–是BeanFactoryPostProcessor的一个子实现类,spring提供的一个工具类,用于解析bean定义中属性值里面的占位符(${:}),此类不能实例化使用

<p>Example XML property with default value:

<pre class="code">
	<property name="url" value="jdbc:${dbname:defaultdb}" />
</pre>

三、初始化

给属性设置值,执行init-method(配置中指定的初始化方法)

实例化+初始化->创建对象(init方法在构造方法之后)

3.1.填充属性

调用populate方法

3.2.设置Aware接口的属性

Aware接口

当Spring容器创建的bean对象在进行具体操作的时候,如果需要容器的其他对象,此时可以将对象实现具体的能拿到该对象Aware接口,来满足当前的需要

例:ApplicationContextAware

public interface ApplicationContextAware extends Aware {
	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

自定义实现该接口可获取ApplicationContext对象

3.3.BeanPostProcessor:before()

3.4.执行init-method

3.3.BeanPostProcessor :after()

例:AbstractAutoProxyCreator 与AOP相关(cglib/jdk动态代理)

在这里插入图片描述

AbstractAutoProxyCreator类是BeanPostProcessor接口的一个子实现类,意味这重写了postProcessBeforeInitialization前置处理方法和postProcessAfterInitialization后置处理方法

AbstractAutoProxyCreator -> postProcessBeforeInitialization()

/**
 * 此处是真正创建aop代理的地方,在实例化之后,初始化之后就行处理
 * 首先查看是否在earlyProxyReferences里存在,如果有就说明处理过了,不存在就考虑是否要包装,也就是代理
 *
 * Create a proxy with the configured interceptors if the bean is
 * identified as one to proxy by the subclass.
 * @see #getAdvicesAndAdvisorsForBean
 */
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
   if (bean != null) {
      // 获取当前bean的key:如果beanName不为空,则以beanName为key,如果为FactoryBean类型,
      // 前面还会添加&符号,如果beanName为空,则以当前bean对应的class为key
      Object cacheKey = getCacheKey(bean.getClass(), beanName);
      // 判断当前bean是否正在被代理,如果正在被代理则不进行封装
      if (this.earlyProxyReferences.remove(cacheKey) != bean) {
         // 如果它需要被代理,则需要封装指定的bean
         return wrapIfNecessary(bean, beanName, cacheKey);
      }
   }
   return bean;
}

AbstractAutoProxyCreator -> wrapIfNecessary()

/**
 * 先判断是否已经处理过,是否需要跳过,跳过的话直接就放进advisedBeans里,表示不进行代理,如果这个bean处理过了,获取通知拦截器,然后开始进行代理
 *
 * Wrap the given bean if necessary, i.e. if it is eligible for being proxied.
 * @param bean the raw bean instance
 * @param beanName the name of the bean
 * @param cacheKey the cache key for metadata access
 * @return a proxy wrapping the bean, or the raw bean instance as-is
 */
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
   // 如果已经处理过,直接返回
   if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {
      return bean;
   }
   // 这里advisedBeans缓存了已经进行了代理的bean,如果缓存中存在,则可以直接返回
   if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
      return bean;
   }
   // 这里isInfrastructureClass()用于判断当前bean是否为Spring系统自带的bean,自带的bean是
   // 不用进行代理的;shouldSkip()则用于判断当前bean是否应该被略过
   if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
      // 对当前bean进行缓存
      this.advisedBeans.put(cacheKey, Boolean.FALSE);
      return bean;
   }

   // Create proxy if we have advice.
   // 获取当前bean的Advices和Advisors
   Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
   // 对当前bean的代理状态进行缓存
   if (specificInterceptors != DO_NOT_PROXY) {
      // 对当前bean的代理状态进行缓存
      this.advisedBeans.put(cacheKey, Boolean.TRUE);
      // 根据获取到的Advices和Advisors为当前bean生成代理对象
      Object proxy = createProxy(
            bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
      // 缓存生成的代理bean的类型,并且返回生成的代理bean
      this.proxyTypes.put(cacheKey, proxy.getClass());
      return proxy;
   }

   this.advisedBeans.put(cacheKey, Boolean.FALSE);
   return bean;
}

AbstractAutoProxyCreator -> createProxy()

/**
 * 进行代理工厂的创建,然后判断是否需要设置proxyTargetClass,以便于后面决定是不是要进行jdk动态代理还是cglib的动态代理
 * 然后把通知器advisors包装下,加入到代理工厂,获取代理对象
 *
 * Create an AOP proxy for the given bean.
 * @param beanClass the class of the bean
 * @param beanName the name of the bean
 * @param specificInterceptors the set of interceptors that is
 * specific to this bean (may be empty, but not null)
 * @param targetSource the TargetSource for the proxy,
 * already pre-configured to access the bean
 * @return the AOP proxy for the bean
 * @see #buildAdvisors
 */
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
      @Nullable Object[] specificInterceptors, TargetSource targetSource) {

   // 给bean定义设置暴露属性
   if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
      AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
   }

   // 创建代理工厂
   ProxyFactory proxyFactory = new ProxyFactory();
   // 获取当前类中相关属性
      proxyFactory.copyFrom(this);
   // 决定对于给定的bean是否应该使用targetClass而不是他的接口代理,检查proxyTargetClass设置以及preserverTargetClass属性
   if (!proxyFactory.isProxyTargetClass()) {
      // 判断是 使用jdk动态代理 还是cglib代理
      if (shouldProxyTargetClass(beanClass, beanName)) {
         proxyFactory.setProxyTargetClass(true);
      }
      else {
         // 添加代理接口
         evaluateProxyInterfaces(beanClass, proxyFactory);
      }
   }

   // 构建增强器
   Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
   proxyFactory.addAdvisors(advisors);
   // 设置到要代理的类
   proxyFactory.setTargetSource(targetSource);
   // 定制代理
   customizeProxyFactory(proxyFactory);

   // 控制代理工程被配置之后,是否还允许修改通知,默认值是false
   proxyFactory.setFrozen(this.freezeProxy);
   if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
   }
   // 真正创建代理对象
   return proxyFactory.getProxy(getProxyClassLoader());
}

ProxyFactory -> getProxy()

public Object getProxy(@Nullable ClassLoader classLoader) {
   // createAopProxy() 用来创建我们的代理工厂
   return createAopProxy().getProxy(classLoader);
}

	/**
	 * 创建AOP代理,如果激活了,就需要有激活通知
	 *
	 * Subclasses should call this to get a new AOP proxy. They should <b>not</b>
	 * create an AOP proxy with {@code this} as an argument.
	 */
	protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			// 监听调用AdvisedSupportListener实现类的activated方法
			activate();
		}
		// 通过AopProxyFactory获得AopProxy,这个AopProxyFactory是在初始化函数中定义的,使用的是DefaultAopProxyFactory
		return getAopProxyFactory().createAopProxy(this);
	}

AopProxy -> getProxy()

在这里插入图片描述

3.3后得到完整的Bean对象,从容器中进行获取contxt.getBean()

为什么是上面的创建顺序

参见:BeanFactory

创建过程

* <p>Bean factory implementations should support the standard bean lifecycle interfaces
* as far as possible. The full set of initialization methods and their standard order is:
* <ol>
* <li>BeanNameAware's {@code setBeanName}
* <li>BeanClassLoaderAware's {@code setBeanClassLoader}
* <li>BeanFactoryAware's {@code setBeanFactory}
* <li>EnvironmentAware's {@code setEnvironment}
* <li>EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
* <li>ResourceLoaderAware's {@code setResourceLoader}
* (only applicable when running in an application context)
* <li>ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
* (only applicable when running in an application context)
* <li>MessageSourceAware's {@code setMessageSource}
* (only applicable when running in an application context)
* <li>ApplicationContextAware's {@code setApplicationContext}
* (only applicable when running in an application context)
* <li>ServletContextAware's {@code setServletContext}
* (only applicable when running in a web application context)
* <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
* <li>InitializingBean's {@code afterPropertiesSet}
* <li>a custom init-method definition
* <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
* </ol>

销毁过程

* <p>On shutdown of a bean factory, the following lifecycle methods apply:
* <ol>
* <li>{@code postProcessBeforeDestruction} methods of DestructionAwareBeanPostProcessors
* <li>DisposableBean's {@code destroy}
* <li>a custom destroy-method definition
* </ol>

在不同的阶段处理不同的工作,如何处理?

观察者模式:监听器+监听事件+多播器(广播器)

SpringBean的分类

  1. 普通对象:我们自定义需要的对象
  2. 容器对象:内置对象(Spring需要的对象)

BeanFactory和FactoryBean的区别

BeanFactory是个Factory,也就是IOC容器或对象工厂,FactoryBean是个Bean。在Spring中,所有的Bean都是由BeanFactory(也就是IOC容器)来进行管理的。但对FactoryBean而言,这个Bean不是简单的Bean,而是一个能生产或者修饰对象生成的工厂Bean,它的实现与设计模式中的工厂模式和修饰器模式类似

FactoryBean

当调用getBean(“XXXbeanName”)时,Spring通过反射机制发现XXXFactoryBean实现了FactoryBean的接口,这时Spring容器就调用接口方法XXXFactoryBean#getObject()方法返回。如果希望获取XXXFactoryBean的实例,则需要在使用getBean(“XXXbeanName”)方法时在beanName前显示的加上"&“前缀:如getBean(”&XXXbeanName");

详情参见

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring 源码分析是一个相对复杂和庞大的话题,无法在一次对话中详细讨论。不过,我可以给你提供一些关于 Spring 源码分析的一般指导和建议。 1. 了解 Spring 的核心模块:Spring 框架是模块化的,每个模块都有不同的功能和职责。在开始源码分析之前,你需要先了解 Spring 的核心模块,如 Spring Core、Spring MVC、Spring Data 等。 2. 阅读官方文档和源码注释:Spring 框架的官方文档和源码注释是你学习和理解源码的重要资源。官方文档提供了对 Spring 各个模块的详细说明,源码注释则解释了代码的作用和实现细节。 3. 调试和跟踪代码:在进行源码分析时,调试器是你的好帮手。通过设置断点、单步跟踪以及观察变量的值,你可以深入理解代码的执行流程和逻辑。 4. 理解设计模式和原理:Spring 框架采用了许多设计模式和原理来实现其功能。在分析源码时,你需要熟悉这些设计模式和原理,例如依赖注入、AOP、工厂模式等。 5. 参考开源社区和博客:Spring 框架是一个非常活跃的开源社区,许多开发者在博客和论坛上分享了他们的源码分析和理解。阅读这些文章可以帮助你更好地理解 Spring 框架的实现细节。 请记住,深入分析 Spring 源码需要耐心和时间投入,同时也需要有一定的 Java 和设计模式的基础。希望这些指导对你有所帮助!如果你有具体的问题或者需要更详细的信息,欢迎继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值