手把手教你看 Spring 源码

程序员考拉

共 18521字,需浏览 38分钟

 · 2021-03-19

公众号关注 “GitHub今日热榜
设为 “星标”,带你挖掘更多开发神器!






Spring类的初始化和实例化的不同



IOC


探究spring的IOC容器


DefaultListableBeanFactory是最终实现类,在代码中可以找到HashMap的影子;IOC容器就是用HashMap装的Bean;


public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
    implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
@Nullable
  private static Class<?> javaxInjectProviderClass;

  static {
    try {
      javaxInjectProviderClass =
          ClassUtils.forName("javax.inject.Provider", DefaultListableBeanFactory.class.getClassLoader());
    }
    catch (ClassNotFoundException ex) {
      // JSR-330 API not available - Provider interface simply not supported then.
      javaxInjectProviderClass = null;
    }
  }


  /** Map from serialized id to factory instance. */
  private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =
      new ConcurrentHashMap<>(8);

  /** Optional id for this factory, for serialization purposes. */
  @Nullable
  private String serializationId;

  /** Whether to allow re-registration of a different definition with the same name. */
  private boolean allowBeanDefinitionOverriding = true;

  /** Whether to allow eager class loading even for lazy-init beans. */
  private boolean allowEagerClassLoading = true;

  /** Optional OrderComparator for dependency Lists and arrays. */
  @Nullable
  private Comparator<Object> dependencyComparator;

  /** Resolver to use for checking if a bean definition is an autowire candidate. */
  private AutowireCandidateResolver autowireCandidateResolver = SimpleAutowireCandidateResolver.INSTANCE;

  /** Map from dependency type to corresponding autowired value. */
  private final Map<Class<?>, Object> resolvableDependencies = new ConcurrentHashMap<>(16);

  /** Map of bean definition objects, keyed by bean name. */
  private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

  /** Map from bean name to merged BeanDefinitionHolder. */
  private final Map<String, BeanDefinitionHolder> mergedBeanDefinitionHolders = new ConcurrentHashMap<>(256);

  /** Map of singleton and non-singleton bean names, keyed by dependency type. */
  private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);

  /** Map of singleton-only bean names, keyed by dependency type. */
  private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);

  /** List of bean definition names, in registration order. */
  private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

  /** List of names of manually registered singletons, in registration order. */
  private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16);

  /** Cached array of bean definition names in case of frozen configuration. */
  @Nullable
  private volatile String[] frozenBeanDefinitionNames;
................
...........
}


BeanFactory:主要方法为getBean(String beanName),该方法根据Bean名称从容器返回对应的Bean


BeanFactory是接口,提供了IOC容器最基本的形式,给具体的IOC容器的实现提供了规范,



发现BeanFactory是Spring的IOC容器核心接口,它的职责包括,实例化,有很多的实现类;



原始的BeanFactory无法支持spring的许多插件,如AOP功能、Web应用等



那么BeanFactroy是否有AOP的影子呢?


找到BeanFactroyAware接口看到很多关键字有proxy类似代理的接口


so 猜想是否跟AOP(面向切面,动态代理)有关



然后点进去其中一个方法(AbstractAutoProxyCreator),发现引入很多跟AOP相关的包


import org.springframework.aop.Advisor;
import org.springframework.aop.Pointcut;
import org.springframework.aop.TargetSource;
import org.springframework.aop.framework.AopInfrastructureBean;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.framework.ProxyProcessorSupport;
import org.springframework.aop.framework.adapter.AdvisorAdapterRegistry;
import org.springframework.aop.framework.adapter.GlobalAdvisorAdapterRegistry;
import org.springframework.aop.target.SingletonTargetSource;


往下看看这个类,做了什么?找几个方法出来;


看看类的注释


此类区分通用拦截器(由创建的所有代理共享)和特定拦截器:每个bean实例唯一。不需要任何通用拦截器。如果存在,则使用interceptorNames属性设置它们。


与{@link org.springframework.aop.framework.ProxyFactoryBean}一样,使用当前工厂中的拦截器名称而不是bean引用来正确处理原型顾问程序和拦截器例如,以支持有状态的混合。{@link #set InterceptorNames interceptorNames}条目支持任何建议类型。如果有大量的豆需要用类似的代理包装,即委托给相同的拦截器,则这种自动代理特别有用。代替x个目标bean的x个重复代理定义,您可以在bean工厂注册一个这样的后处理器,以达到相同的效果


public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport 
    implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware {
    /**
   *设置公共拦截器。这些必须是当前工厂中的bean名称
   */

  public void setInterceptorNames(String... interceptorNames) {
    this.interceptorNames = interceptorNames;
  }
/**
  为给定的bean创建一个AOP代理
   */

  protected Object createProxy(Class<?> beanClass, @Nullable String beanName,
      @Nullable 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);
    proxyFactory.addAdvisors(advisors);
    proxyFactory.setTargetSource(targetSource);
    customizeProxyFactory(proxyFactory);
    proxyFactory.setFrozen(this.freezeProxy);
        
    if (advisorsPreFiltered()) {
      proxyFactory.setPreFiltered(true);
    }
    return proxyFactory.getProxy(getProxyClassLoader());
  }
    
    
}


AbstractAutoProxyCreator类关系UML图



说明AOP横切在Bean的生命周期中


AOP


Spring 通过 AbstractAutoProxyCreator 来创建 AOP 代理,AbstractAutoProxyCreator 是一个抽象类,它实现了 BeanPostProcessor 接口,用于在 bean 初始化完成之后创建它的代理(从上面IOC容器创建Bean过程中有点体现);


在AbstractAutoProxyCreator类关系UML图中找到一个特殊的接口—>BeanPostProcessor


划重点:


  • 与工厂挂钩,允许自定义修改新bean实例,如检查标记接口或使用代理包装bean;

  • 普通的{@code BeanFactory}允许以编程方式注册后处理器,并将其应用于通过bean工厂创建的所有bean中;跟上面的AOP横切BeanFactroy联系上了;


/**
 工厂挂钩,允许自定义修改新bean实例-例如,检查标记接口或使用代理包装bean。<p>通常,通过标记接口*或类似对象填充bean的后处理器将实现{@link #postProcessBeforeInitialization},而使用代理包装bean的后处理器通常将实现{@link #postProcessAfterInitialization}。<h3>注册</h3> <p> {@ code ApplicationContext}可以在其bean定义中自动检测{@code BeanPostProcessor} bean,并将这些后处理器应用于随后创建的任何bean。普通的{@code BeanFactory}允许以编程方式注册后处理器,并将其应用于通过bean工厂创建的所有bean
 */

public interface BeanPostProcessor {

  /**
   在任何bean 初始化回调(如InitializingBean的{@code afterPropertiesSet} 或自定义的init-method)之前,将此{@code BeanPostProcessor}应用于给定的新bean实例<i> </ i>。该bean将已经用属性值填充。返回的bean实例也可能是原始实例的包装;
   */

  @Nullable
  default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }

  /**
在任何bean 初始化回调(例如InitializingBean的{@code afterPropertiesSet} 或自定义的初始化方法)之后,将此{@code BeanPostProcessor}应用于给定的新bean实例。该bean将已经用属性值填充。返回的bean实例可能是原始实例的包装。对于FactoryBean,将为FactoryBean 实例和由FactoryBean创建的对象(从Spring 2.0开始)调用此回调。后处理器可以通过相应的{@code bean instanceof FactoryBean}检查来决定是应用到FactoryBean还是创建的对象,还是两者都应用。
   */

  @Nullable
  default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;
  }

}


在来看这张图(IOC容器工作过程)


BeanPostProcessor就是AOP切入的位置,处在对象的生命周期中;



BeanFactoryPostProcessor(初始化Bean,如上图)


public interface BeanFactoryPostProcessor {
  /**
  在标准初始化之后,修改应用程序上下文的内部bean工厂。所有bean定义都将被加载,但是还没有实例化bean *。这甚至可以覆盖或添加*属性,甚至可以用于初始化bean。
   */

  void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;}


另外提点东西(来自面试)


BeanFactory 简介以及它 和FactoryBean的区别(阿里面试)


FactoryBean接口是什么?


看看官方注释:


在BeanFactory中的对象实现的接口,这些对象本身是个单个对象的工厂,如果这些对象实现FactoryBean接口,它将用作对象公开的工厂,而不是直接将自身公开;



好像还是有点蒙吧看看其他解释


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

    

FactoryBean接口用的是Class getObjectType();可以理解为高级定制Bean;


看FactoryBean接口抽象类(AbstractFactoryBean)


public abstract class AbstractFactoryBean<T>
    implements FactoryBean<T>, BeanClassLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean 
{
  /** Logger available to subclasses. */
  protected final Log logger = LogFactory.getLog(getClass());
  private boolean singleton = true;
  @Nullable
  private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
  @Nullable
  private BeanFactory beanFactory;
  private boolean initialized = false;
  @Nullable
  private T singletonInstance;
  @Nullable
  private T earlySingletonInstance;

  /**
      设置是否应该创建一个单例,或者在每个请求上创建一个新对象*否则。默认值为{@code true}(单例)。
   */

  public void setSingleton(boolean singleton) {
    this.singleton = singleton;
  }
  @Override
  public boolean isSingleton() {
    return this.singleton;
  }
  @Override
  public void setBeanClassLoader(ClassLoader classLoader) {
    this.beanClassLoader = classLoader;
  }
  @Override
  public void setBeanFactory(@Nullable BeanFactory beanFactory) {
    this.beanFactory = beanFactory;
  }
  /**
   返回运行该bean的BeanFactory
   */

  @Nullable
  protected BeanFactory getBeanFactory() {
    return this.beanFactory;
  }

  /**
      从运行该bean的BeanFactory获取一个bean类型转换器
   */

  protected TypeConverter getBeanTypeConverter() {
    BeanFactory beanFactory = getBeanFactory();
    if (beanFactory instanceof ConfigurableBeanFactory) {
      return ((ConfigurableBeanFactory) beanFactory).getTypeConverter();
    }
    else {
      return new SimpleTypeConverter();
    }
  }
    /**
       公开单例实例(用于通过“早期单例”代理访问)。返回此FactoryBean持有的单例实例
   */

  @Nullable
  private T getSingletonInstance() throws IllegalStateException {
    Assert.state(this.initialized, "Singleton instance not initialized yet");
    return this.singletonInstance;
  }
}


看完FactoryBean接口抽象类(AbstractFactoryBean)基本的代码后,发现什么?


FactoryBean基于BeanFactory,FactoryBean是一个能生产或者修饰对象生成的工厂Bean;


FactoryBean中定义了一个Spring Bean的很重要的三个特性:是否单例、Bean类型、Bean实例


ApplicationContext接口,由BeanFactory接口派生而来


看到ApplicationContext接口,提供应用程序配置的中央接口。在应用程序运行时为只读,但如果实现支持,则可以重新加载。


ApplicationContext提供:


  • 用于访问应用程序组件的Bean工厂方法。继承自{@link org.springframework.beans.factory.ListableBeanFactory}。 

  • 以通用方式加载文件资源的能力。继承自{@link org.springframework.core.io.ResourceLoader}接口。

  • 将事件发布到注册的侦听器的能力。继承自{@link ApplicationEventPublisher}接口。

  • 解决消息的能力,支持国际化。继承自{@link MessageSource}接口。

  • 从父上下文继承。在后代上下文中的定义将始终优先。例如,这意味着整个Web应用程序都可以使用单个父上下文,而每个servlet都有自己的子上下文,而该子上下文独立于任何其他servlet的子上下文。

  • 除了标准的{@link org.springframework.beans.factory.BeanFactory}生命周期功能之外,ApplicationContext实现还检测并调用{@link ApplicationContextAware} Bean以及{@link ResourceLoaderAware },{@link ApplicationEventPublisherAware}和{@link MessageSourceAware} bean。


public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
    MessageSource, ApplicationEventPublisher, ResourcePatternResolver 
{

  /**
      返回此应用程序上下文的唯一ID
   */

  @Nullable
  String getId();

  /**
  返回此上下文所属的已部署应用程序的名称
   */

  String getApplicationName();

  /**
     返回此上下文的显示名称
   */

  String getDisplayName();

  /**
  返回首次加载此上下文时的时间戳
   */

  long getStartupDate();

  /**
   返回父级上下文,如果没有父级,则返回{@code null}
   */

  @Nullable
  ApplicationContext getParent();

  /**
  针对此上下文公开AutowireCapableBeanFactory功能。* <p>应用程序代码通常不使用此功能,除非是为了*初始化存在于应用程序上下文之外的bean实例,*将Spring bean生命周期(全部或部分)应用于它们。* <p>或者,通过{@link ConfigurableApplicationContext}接口公开的内部BeanFactory也提供对{{link AutowireCapableBeanFactory}接口的访问。本方法主要*用作ApplicationContext接口上的便捷特定工具。* <p> <b>注意:从4.2开始,在关闭应用程序上下文之后,此方法将始终抛出IllegalStateException *。</ b>在当前的Spring Framework *版本中,只有可刷新的应用程序上下文才具有这种行为;从4.2开始,*所有应用程序上下文实现都将必须遵守。* @为此上下文返回AutowireCapableBeanFactory *如果上下文不支持{@link AutowireCapableBeanFactory}接口,或者尚不具有支持自动连线功能的bean工厂,则抛出IllegalStateException(例如,如果{@code refresh()}具有*从未调用过),或者上下文已经关闭* @see ConfigurableApplicationContext#refresh()* @see ConfigurableApplicationContext#getBeanFactory()* /
   */

  AutowireCapableBeanFactory getAutowireCapableBeanFactory() throws IllegalStateException;


ApplicationContext接口UML类图



ApplicationContext有两个主要的实现类:ClassPathXmlApplicationContext:默认从类路径加载配置文件,还有FileSystemXmlApplicationContext:默认从文件系统中装载配置文件


WebApplicationContext


提供Web应用程序配置的界面。在应用程序运行时为只读,但是如果实现支持,则可以重新加载。此接口在通用ApplicationContext接口中添加了一个{@code getServletContext()}方法,并定义了一个众所周知的应用程序属性名称,该名称必须在引导过程中绑定到根上下文。类似于通用应用程序上下文,Web应用程序上下文是分层的。每个应用程序只有一个根上下文,而应用程序中的每个servlet(包括MVC框架中的调度程序servlet)都有自己的子上下文。除了标准的应用程序上下文生命周期功能外,WebApplicationContext实现还需要检测{@link ServletContextAware} bean,并相应地调用{@code setServletContext}方法


public interface WebApplicationContext extends ApplicationContext {

  /**
  Context属性,用于在成功启动时将根WebApplicationContext绑定到该属性。* <p>注意:如果根上下文的启动失败,则此属性可以包含*异常或错误作为值。使用WebApplicationContextUtils方便*查找根WebApplicationContext。
   */

  String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";

  /**
  请求范围的范围标识符:“ request”。*除了标准范围“ singleton”和“ prototype”之外,还受支持。
   */

  String SCOPE_REQUEST = "request";

  /**
  会话范围的范围标识符:“session”。*除了标准范围“ singleton”和“ prototype”之外,还受支持。
   */

  String SCOPE_SESSION = "session";

  /**
  全局Web应用程序范围的范围标识符:“application”。*除了标准范围“ singleton”和“ prototype”之外,还受支持。
   */

  String SCOPE_APPLICATION = "application";

  /**
  工厂中ServletContext环境Bean的名称
   */

  String SERVLET_CONTEXT_BEAN_NAME = "servletContext";

  /**
  工厂中ServletContext init-params环境Bean的名称
   */

  String CONTEXT_PARAMETERS_BEAN_NAME = "contextParameters";

  /**
  工厂中ServletContext属性环境bean的名称
   */

  String CONTEXT_ATTRIBUTES_BEAN_NAME = "contextAttributes";


  /**
  返回此应用程序的标准Servlet API ServletContext
   */

  @Nullable
  ServletContext getServletContext();
}


WebApplicationContext的UML类图(从图中可以发现WebApplicationContext扩展了ApplicationContext的功能,ApplicationContext扩展了BeanFactory的功能。)



这几个接口间的区别


1.BeanFactory和ApplicationContext, WebApplicationContext初始化区别:BeanFactory在初始化容器时并没有实例化Bean,而是在第一次访问到目标Bean时才实例化该Bean;而ApplicationContext会在初始化上下文时实例化所有的单例的Bean。WebApplicationContext的初始化需要servletContext实例(getServletContext();),即初始化需要拥有web容器,我们需要在web.xml中配置自启动的servlet或web容器监听器(servletContextListener)


2.Bean的作用域


在BeanFactory和ApplicationContext中的Bean的作用域有两种:singleton和prototype,在WebApplicationContext中的Bean的作用域有三种:request,session和globalSession。

    

  • singleton:在IOC容器中仅存在一个Bean实例,Bean以单例方式存在,外部引用都指向这个Bean

  • prototype:每次调用Bean都返回一个新实例

  • request:在同一个Http请求的Bean相同,每个Http请求创建一个新的Bean。

  • session:在Http请求对应同一个session时对应同一个Bean。

  • globalSession:一般的web应用中globalSession等价于session,只有在portlet web应用中才存在globalSession概念。




出处:https://blog.csdn.net/weixin_44313584/article/details/114785885








关注GitHub今日热榜,专注挖掘好用的开发工具,致力于分享优质高效的工具、资源、插件等,助力开发者成长!







点个在看 你最好看


浏览 50
点赞
评论
收藏
分享

手机扫一扫分享

举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

举报