栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring(四)IOC容器的高级特性

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring(四)IOC容器的高级特性

文章目录
    • 一、IOC 高级特性
      • 1.1 延迟加载
        • 1.1.1 延迟加载的使用
        • 1.1.2 延迟加载流程
      • 1.2 FactoryBean和BeanFactory
      • 1.3 自动装配
      • 1.4 两种后置处理器
    • 二、Bean生命周期的相关问题
      • 2.1 Spring框架中Bean的生命周期
        • 2.1.1 简述
        • 2.1.2 详述
        • 2.1.3 相关生命周期方法的使用
      • 2.2 用xml配置的方式重写init和destroy方法

本系列文章:
  Spring(一)IOC、DI、@Autowired、@Resource、作用域
  Spring(二)IOC容器的初始化流程
  Spring(三)IOC容器的依赖注入流程
  Spring(四)IOC容器的高级特性
  Spring(五)AOP、事务
  Spring(六)Spring MVC
  Spring(七)SpringBoot
  Spring(八)Spring Cloud

一、IOC 高级特性

  通过前面章节中对Spring IOC容器的源码分析,我们已经基本上了解了Spring IOC容器对Bean定义资源的定位、载入和注册过程,同时也清楚了当用户通过 getBean()方法向IOC容器获取被管理的Bean时,IOC 容器对 Bean 进行的初始化和依赖注入过程,这些是 Spring IOC 容器的基本功能特性。
  Spring IOC容器还有一些高级特性,如使用lazy-init属性对Bean预初始化、FactoryBean产生或者修饰Bean对象的生成、IOC容器初始化Bean过程中使用BeanPostProcessor后置处理器对Bean声明周期事件管理和IOC容器的autowiring自动装配功能等。

1.1 延迟加载

   IOC 容器的初始化过程就是对 Bean定义资源的定位、载入和注册,此时容器对 Bean 的依赖注入并没有发生,依赖注入主要是在应用程序第一次向容器索取 Bean 时,通过 getBean()方法的调用完成。
  当 Bean 定义资源的元素中配置了lazy-init=false属性时,容器将会在初始化的时候对所配置的 Bean 进行预实例化,Bean的依赖注入在容器初始化的时候就已经完成。这样,当应用程序第一次向容器索取被管理的Bean时,就不用再初始化和对Bean进行依赖注入了,直接从容器中获取已经完成依赖注入的现成Bean,可以提高应用第一次向容器获取Bean的性能。

1.1.1 延迟加载的使用

  ApplicationContext容器默认在启动服务器时将所有单例Bean提前进行实例化。提前实例化意味着作为初始化过程的一部分,ApplicationContext实例会创建并配置所有的单例Bean。
  比如:

	
	
	

  lazy-init="false",立即加载,表示在spring启动时,立刻进行实例化。
  如果不想让个单例Bean在ApplicationContext实现初始化时被提前实例化,那么可以将Bean
设置为延迟实例化。示例:

	

  设置lazy-init为true的Bean将不会在ApplicationContext启动时提前被实例化,而是第一次向容器通过getBean索取Bean时实例化的。
  如果一个设置了立即加载的bean1,引用了一个延迟加载的bean2,那么bean1在容器启动时被实例化,而bean2由于被bean1引用,所以也被实例化,这种情况也符合延时加载的Bean在第一次调用时才被实例化的规则。
  如果一个bean的scope属性为scope=“pototype” 时,即使设置了lazy-init="false",容器启动时也不会实例化Bean,而是调用getBean方法实例化的。

  • 延迟加载场景
      1)开启延迟加载一定程度提高容器启动和运转性能。
      2)对于不常使用的Bean设置延迟加载,这样偶尔使用的时候再加载,不必要从一开始就让该Bean占用资源。
1.1.2 延迟加载流程
  • 1、refresh()方法
      先从IOC 容器的初始化过程开始,我们知道IOC容器读入已经定位的 Bean 定义资源是从 refresh()方法开始的,我们首先从 AbstractApplicationContext 类的 refresh()方法入手分析:
	//refresh方法主要为IOC容器Bean的生命周期管理提供条件,在获取了BeanFactory之后都是在向该容器
	//注册信息源和生命周期事件。在创建IOC容器前,如果已经有容器存在,需要把已有的容器销毁和关闭,
	//以保证在refresh()方法之后使用的是新创建的IOC容器。
	@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 调用容器准备刷新的方法,获取容器的当前时间,同时给容器设置同步标识
			prepareRefresh();

			// 获得beanFactory
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// beanFactory的预准备工作,对beanfactory配置容器特性,例如类加载器、事件处理器等
			prepareBeanFactory(beanFactory);

			try {
				//beanFactory准备工作完成之后要进行的后置处理(BeanPost事件处理)工作,留给子类扩展使用
				postProcessBeanFactory(beanFactory);

				//调用所有注册的BeanFactoryPostProcessor的Bean
				invokeBeanFactoryPostProcessors(beanFactory);

				//为BeanFactory注册BeanPost事件处理器
				//BeanPostProcessors是Bean后置处理器,用于监听容器触发的事件
				registerBeanPostProcessors(beanFactory);

				//初始化MessageSource信息源,即国际化处理、消息绑定、消息解析
				initMessageSource();

				//初始化容器事件传播器
				initApplicationEventMulticaster();

				//留给子类来初始化其他的bean
				onRefresh();

				//在所有注册的bean中查找ApplicationListener,为事件广播器注册事件监听器
				registerListeners();

				//初始化所有剩下的单实例bean
				finishBeanFactoryInitialization(beanFactory);

				//完成刷新过程,初始化容器的生命周期事件处理器,并发布容器的生命周期事件
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// 销毁已经创建的Bean
				destroyBeans();

				// 取消刷新操作,重置容器的同步标识
				cancelRefresh(ex);

				throw ex;
			}

			finally {
				// 重置公共缓存
				resetCommonCaches();
			}
		}
	}

  在 refresh()方法中ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();启动了 Bean 定义资源的载入、注册过程,而finishBeanFactoryInitialization方法是对注册后的 Bean定义中的预实例化(lazy-init=false,Spring 默认就是预实例化,即为 true)的 Bean 进行处理的地方。

  • 2、finishBeanFactoryInitialization处理预实例化Bean
      当Bean定义资源被载入IOC容器之后,容器将Bean定义资源解析为容器内部的数据结构 BeanDefinition注册到容器中,AbstractApplicationContext 类中的 finishBeanFactoryInitialization()方法对配置了预实例化属性的 Bean 进行预初始化过程:
	//对配置了lazy-init属性的bean进行实例化处理
	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		//这是Spring3之后增加的代码,为容器准备一个转换服务,在对某些Bean属性进行转换时使用
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}

		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		//为了使类型匹配,停止使用临时的类加载器
		beanFactory.setTempClassLoader(null);

		//缓存容器中所有注册的BeanDefinition元数据,以防被修改
		beanFactory.freezeConfiguration();

		//对配置了lazy-init属性的单例模式的Bean进行预实例化处理
		beanFactory.preInstantiateSingletons();
	}

  ConfigurableListableBeanFactory是 一 个 接 口 , 其preInstantiateSingletons()方法由其子类DefaultListableBeanFactory提供。

  • 3、DefaultListableBeanFactory 对配置 lazy-init 属性单例Bean的预实例化
	@Override
	public void preInstantiateSingletons() throws BeansException {
		if (logger.isTraceEnabled()) {
			logger.trace("Pre-instantiating singletons in " + this);
		}

		//获取容器中的所有bean,依次进行初始化和创建对象
		List beanNames = new ArrayList<>(this.beanDefinitionNames);

		for (String beanName : beanNames) {
			//获取bean的定义信息
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			//bean不是抽象的、是单实例的、是懒加载的
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
				//判断是否是FactoryBean,是否是实现FactoryBean接口的bean
				if (isFactoryBean(beanName)) {
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						final FactoryBean factory = (FactoryBean) bean;
						//标识是否需要实例化
						boolean isEagerInit;
						if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
							isEagerInit = AccessController.doPrivileged((PrivilegedAction)
											((SmartFactoryBean) factory)::isEagerInit,
									getAccessControlContext());
						}
						else {
							isEagerInit = (factory instanceof SmartFactoryBean &&
									((SmartFactoryBean) factory).isEagerInit());
						}
						if (isEagerInit) {
							getBean(beanName);
						}
					}
				}
				else {
					//不是工厂Bean,利用getBean创建对象
					getBean(beanName);
				}
			}
		}

		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}
 

  可以看出,如果设置了lazy-init属性,则容器在完成Bean定义的注册之后,会通过getBean方法,触发对指定Bean的初始化和依赖注入过程,这样当应用第一次向容器索取所需的Bean时,容器不再需要对Bean进行初始化和依赖注入,直接从已经完成实例化和依赖注入的Bean中取一个现成的Bean,这样就提高了第一次获取Bean的性能。

1.2 FactoryBean和BeanFactory

  BeanFactory:Bean工厂,是一个工厂(Factory),Spring IOC容器的最顶层接口就是这个BeanFactory,它的作用是管理Bean,即实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
  FactoryBean:工厂Bean,是一个Bean,作用是产生其他bean实例。通常情况下,这种 Bean没有什么特别的要求,仅需要提供一个工厂方法,该方法用来返回其他Bean实例。通常情况下,Bean 无须自己实现工厂模式,Spring容器担任工厂角色;但少数情况下,容器中的Bean本身就是工厂,其作用是产生其它Bean实例。
  当用户使用容器本身时,可以使用转义字符&来得到FactoryBean本身,以区别通过 FactoryBean产生的实例对象和FactoryBean对象本身。在BeanFactory中通过如下代码定义了该转义字符:

	String FACTORY_BEAN_PREFIX = "&";

  比如:myJndiObject是一个FactoryBean,则使用&myJndiObject得到的是myJndiObject对象,而不是myJndiObject产生出来的对象。

  • 1、FactoryBean 源码
//工厂Bean,用于产生其他对象 
public interface FactoryBean { 
    //获取容器管理的对象实例 
    @Nullable 
    T getObject() throws Exception; 
    //获取 Bean 工厂创建的对象的类型 
    @Nullable 
    Class getObjectType(); 
    //Bean 工厂创建的对象是否是单态模式,如果是单态模式,则整个容器中只有一个实例 
    //对象,每次请求都返回同一个实例对象 
    default boolean isSingleton() { 
        return true; 
    } 
}
  • 2、AbstractBeanFactory的getBean()方法调用FactoryBean
      在前面我们分析Spring IOC容器实例化Bean并进行依赖注入过程的源码时,提到在getBean()方法触发容器实例化Bean的时候会调用AbstractBeanFactory的doGetBean()方法来进行实例化的过程:
	//真正实现向IOC容器获取Bean的功能,也是触发依赖注入功能的地方
	@SuppressWarnings("unchecked")
	protected  T doGetBean(final String name, @Nullable final Class requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

		//根据指定的名称获取被管理的Bean的名称
		//如果指定的是别名,将别名转换为规范的Bean名称
		final String beanName = transformedBeanName(name);
		Object bean;

		//直接尝试从缓存获取是否已经有被创建过的单例的Bean
		Object sharedInstance = getSingleton(beanName);
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				//如果单例模式的Bean被创建,则直接返回
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			//获取给定Bean的实力对象,主要完成FactoryBean的相关处理
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
			//缓存中没有单例模式的Bean,缓存中已经有原型模式的Bean,但是由于循环引用导致实例化对象失败
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}

			//对IOC容器中是否存在指定名称的BeanDefinition进行检查,首先检查是否能在
			//当前的BeanFactory中获取所需要的Bean。如果不能再委托当前容器的父容器去
			//查找,如果还是找不到则沿着继承关系继续查找
			BeanFactory parentBeanFactory = getParentBeanFactory();
			//当前容器的父容器存在,且当前容器中不存在指定名称的Bean
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				//解析指定Bean名称的原始名称
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				//递归到beanFactory中寻找
				else if (args != null) {
					//委派父容器根据指定名称和显式的参数查找
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					//委派父容器根据指定名称和类型查找
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					//委派父容器根据指定名称查找
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}

			//创建的Bean是否需要进行类型验证
			if (!typeCheckOnly) {
				//向容器标记指定的Bean已经被创建
				markBeanAsCreated(beanName);
			}

			try {
				//根据指定Bean名称获取其父级Bean定义,主要解决Bean继承时子类和父类公共属性问题
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);

				//获取当前bean所有依赖Bean的名称
				String[] dependsOn = mbd.getDependsOn();
				//如果当前Bean有依赖
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						//把能依赖Bean注册给当前依赖的Bean
						registerDependentBean(dep, beanName);
						try {
							//递归调用,获取Bean
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}

				//创建单例模式的Bean的实例对象
				if (mbd.isSingleton()) {
					//调用匿名内部类创建Bean实例对象
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							//从单例模式的Bean缓存中清除实例对象
							destroySingleton(beanName);
							throw ex;
						}
					});
					//获取给定Bean的实力对象
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}
				//IOC容器创建原型模式的Bean实例对象
				else if (mbd.isPrototype()) {
					//prototype模式的创建(new)
					//原型模式每次都会创建一个新的对象
					Object prototypeInstance = null;
					try {
						//回调方法,注册当前创建的原型对象
						beforePrototypeCreation(beanName);
						//创建指定Bean的对象实例
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						//回调方法,告诉IOC容器不再创建指定Bean的原型对象
						afterPrototypeCreation(beanName);
					}
					//获取指定Bean的实例对象
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				else {
					//创建的Bean既不是单例模式也不是原型模式,创建其他生命周期的Bean
					String scopeName = mbd.getScope();
					final Scope scope = this.scopes.get(scopeName);
					//如果Bean定义资源中没有配置生命周期范围,则Bean定义不合法
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						//调用匿名内部类,获取一个指定生命周期范围的实例
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						//获取指定Bean的实例对象
						bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						throw new BeanCreationException(beanName,
								"Scope '" + scopeName + "' is not active for the current thread; consider " +
								"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
								ex);
					}
				}
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}

		// 对创建的Bean实例对象进行类型检查
		if (requiredType != null && !requiredType.isInstance(bean)) {
			try {
				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
				}
				return convertedBean;
			}
			catch (TypeMismatchException ex) {
				if (logger.isTraceEnabled()) {
					logger.trace("Failed to convert bean '" + name + "' to required type '" +
							ClassUtils.getQualifiedName(requiredType) + "'", ex);
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}

	protected Object getObjectForBeanInstance(
			Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {

		// Don't let calling code try to dereference the factory if the bean isn't a factory.
		if (BeanFactoryUtils.isFactoryDereference(name)) {
			if (beanInstance instanceof NullBean) {
				return beanInstance;
			}
			if (!(beanInstance instanceof FactoryBean)) {
				throw new BeanIsNotAFactoryException(beanName, beanInstance.getClass());
			}
		}

		if (!(beanInstance instanceof FactoryBean) || BeanFactoryUtils.isFactoryDereference(name)) {
			return beanInstance;
		}

		Object object = null;
		if (mbd == null) {
			object = getCachedObjectForFactoryBean(beanName);
		}
		if (object == null) {
			//beanInstance一定是FactoryBean类型
			FactoryBean factory = (FactoryBean) beanInstance;
			//如果从Bean工厂生产的Bean是单例的,则缓存
			if (mbd == null && containsBeanDefinition(beanName)) {
				//从容器中获取指定名称的Bean定义,如果继承基类,则合并基类相关属性
				mbd = getMergedLocalBeanDefinition(beanName);
			}
			//如果从容器中得到Bean定义信息,并且Bean定义信息不是虚构的
			//则让工厂Bean生产Bean实例对象
			boolean synthetic = (mbd != null && mbd.isSynthetic());
			//实现工厂Bean生产Bean对象实例的过程
			object = getObjectFromFactoryBean(factory, beanName, !synthetic);
		}
		return object;
	}

  在上面获取给定Bean的实例对象的getObjectForBeanInstance()方法中,会调用 FactoryBeanRegistrySupport类的 getObjectFromFactoryBean()方法,该方法实现了 Bean 工厂生产 Bean 实例对象。

  • 3、AbstractBeanFactory 生产 Bean 实例对象
      AbstractBeanFactory 类中生产 Bean 实例对象的主要源码:
	//Bean工厂生产Bean实例对象
	protected Object getObjectFromFactoryBean(FactoryBean factory, String beanName, boolean shouldPostProcess) {
		//Bean工厂是单例模式,并且Bean工厂缓存中存在指定名称的Bean实例对象
		if (factory.isSingleton() && containsSingleton(beanName)) {
			//多线程同步,以防止数据不一致
			synchronized (getSingletonMutex()) {
				//直接从Bean工厂缓存中获取指定名称的Bean实例对象
				Object object = this.factoryBeanObjectCache.get(beanName);
				//Bean工厂缓存中没有指定名称的实例对象,则生产该实例对象
				if (object == null) {
					//生产指定Bean的实例对象
					object = doGetObjectFromFactoryBean(factory, beanName);
					Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
					if (alreadyThere != null) {
						object = alreadyThere;
					}
					else {
						if (shouldPostProcess) {
							if (isSingletonCurrentlyInCreation(beanName)) {
								// Temporarily return non-post-processed object, not storing it yet..
								return object;
							}
							beforeSingletonCreation(beanName);
							try {
								object = postProcessObjectFromFactoryBean(object, beanName);
							}
							catch (Throwable ex) {
								throw new BeanCreationException(beanName,
										"Post-processing of FactoryBean's singleton object failed", ex);
							}
							finally {
								afterSingletonCreation(beanName);
							}
						}
						if (containsSingleton(beanName)) {
							this.factoryBeanObjectCache.put(beanName, object);
						}
					}
				}
				return object;
			}
		}
		//调用Bean工厂的getObject方法生产指定Bean的实例对象
		else {
			Object object = doGetObjectFromFactoryBean(factory, beanName);
			if (shouldPostProcess) {
				try {
					object = postProcessObjectFromFactoryBean(object, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", ex);
				}
			}
			return object;
		}
	}

	//调用Bean工厂的getObject方法生产指定Bean的实例对象
	private Object doGetObjectFromFactoryBean(final FactoryBean factory, final String beanName)
			throws BeanCreationException {

		Object object;
		try {
			if (System.getSecurityManager() != null) {
				AccessControlContext acc = getAccessControlContext();
				try {
					//实现PrivilegedExceptionAction接口的匿名内部类
					//根据JVM检查权限,然后决定BeanFactory创建实例对象
					object = AccessController.doPrivileged((PrivilegedExceptionAction) factory::getObject, acc);
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
				//直接调用getobject方法创建对象
				object = factory.getObject();
			}
		}
		catch (FactoryBeanNotInitializedException ex) {
			throw new BeanCurrentlyInCreationException(beanName, ex.toString());
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "FactoryBean threw exception on object creation", ex);
		}

		//创建出来的对象实例为null,或者因为单例对象正在创建而返回null
		if (object == null) {
			if (isSingletonCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(
						beanName, "FactoryBean which is currently in creation returned null from getObject");
			}
			object = new NullBean();
		}
		return object;
	}
 

  可以看出,BeanFactory接口调用其实现类的getObject方法来实现创建Bean实例对象的功能。

  • 4、工厂Bean的实现类getObject方法创建Bean实例对象
      FactoryBean的实现类有非常多,比如:Proxy、RMI、JNDI、ServletContextFactoryBean 等等,FactoryBean接口为Spring容器提供了一个很好的封装机制,具体的getObject()有不同的实现类根据不同的实现策略来具体提供,我们分析一个最简单的AnnotationTestFactoryBean的实现源码:

      其他的Proxy,RMI,JNDI等等,都是根据相应的策略提供getObject的实现。
  • 5、BeanPostProcessor后置处理器的实现
      BeanPostProcessor后置处理器是SpringIOC容器经常使用到的一个特性,这个Bean后置处理器是一个监听器,可以监听容器触发的Bean声明周期事件。后置处理器向容器注册以后,容器中管理的Bean就具备了接收IOC容器事件回调的能力。
      BeanPostProcessor的使用非常简单,只需要提供一个实现接口BeanPostProcessor的实现类,然后在Bean的配置文件中设置即可。
      BeanPostProcessor的源码:

      这两个回调的入口都是和容器管理的Bean的生命周期事件紧密相关,可以为用户提供在 SpringIOC容器初始化Bean过程中自定义的处理操作。
      BeanPostProcessor后置处理器的调用发生在SpringIOC容器完成对Bean实例对象的创建和属性的依赖注入完成之后,在对 Spring 依赖注入的源码分析过程中我们知道,当应用程序第一次调用 getBean 方法(lazy-init预实例化除外)向 SpringIOC容器索取指定 Bean 时触发 SpringIOC 容器创建 Bean 实例对象并进行依赖注入的过程,其中真正实现创建 Bean 对象并进行依赖注入的方法是 AbstractAutowireCapableBeanFactory类的doCreateBean方法,主要源码:

      可以看出:为 Bean 实例对象添加BeanPostProcessor后置处理器的入口的是initializeBean方法。
      同样在AbstractAutowireCapableBeanFactory类中,initializeBean方法实现为容器创建的Bean实例对象添加BeanPostProcessor后置处理器:


      BeanPostProcessor是一个接口,其初始化前的操作方法和初始化后的操作方法均委托其实现子类来实现,在Spring中,BeanPostProcessor 的实现子类非常的多,分别完成不同的操作,如:AOP 面向切面编程的注册通知适配器、Bean 对象的数据校验、Bean 继承属性/方法的合并等等,我们以最简单的 AOP 切面织入来简单了解其主要的功能。
      AdvisorAdapterRegistrationManager是BeanPostProcessor的一个实现类,其主要的作用为容器中管理的Bean注册一个面向切面编程的通知适配器,以便在Spring容器为所管理的Bean进行面向切面编程时提供方便,其源码:

      其他的BeanPostProcessor接口实现类的也类似,都是对Bean对象使用到的一些特性进行处理,或者向IOC容器中注册,为创建的Bean实例对象做一些自定义的功能增加,这些操作是容器初始化 Bean时自动触发的,不需要人为的干预。
1.3 自动装配

  Spring IOC容器提供了两种管理Bean依赖关系的方式:

  • 显式管理:通过BeanDefinition的属性值和构造方法实现Bean依赖关系管理。
  • autowiring:Spring IOC容器的依赖自动装配功能,不需要对Bean属性的依赖关系做显式的声明,只需要在配置好autowiring属性,IOC 容器会自动使用反射查找属性的类型和名称,然后基于属性的类型或者名称来自动匹配容器中管理的Bean,从而自动地完成依赖注入。

  通过对autowiring自动装配特性的理解,我们知道容器对Bean的自动装配发生在容器对Bean依赖注入的过程中。在前面对 Spring IOC 容器的依赖注入过程源码分析中,我们已经知道了容器对 Bean 实例对象的属性注入的处理发生在 AbstractAutoWireCapableBeanFactory类中的populateBean()方法中,我们通过程序流程分析 autowiring 的实现原理:

  • 1、AbstractAutoWireCapableBeanFactory对Bean实例进行属性依赖注入
      应用第一次通过getBean()方法(配置了lazy-init预实例化属性的除外)向IOC容器索取Bean时,容器创建Bean实例对象,并且对Bean实例对象进行属性依赖注入,AbstractAutoWireCapableBeanFactory 的populateBean()方法就是实现Bean属性依赖注入的功能,其主要源码:

  • 2、Spring IOC 容器根据 Bean 名称或者类型进行 autowiring 自动依赖注入
	//根据类型对属性进行自动依赖注入
	protected void autowireByType(
			String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
		//获取用户定义的类型转化器
		TypeConverter converter = getCustomTypeConverter();
		if (converter == null) {
			converter = bw;
		}
		//存放解析的要注入的属性
		Set autowiredBeanNames = new LinkedHashSet<>(4);
		//对Bean对象中非简单属性(不是简单继承的对象,如8种原始类型、字符等都是简单属性)进行处理
		String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
		for (String propertyName : propertyNames) {
			try {
				//获取指定属性名称的属性描述其
				PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
				// Don't try autowiring by type for type Object: never makes sense,
				// even if it technically is a unsatisfied, non-simple property.
				//不对Object类型的属性进行autowiring自动依赖注入
				if (Object.class != pd.getPropertyType()) {
					//获取属性的setter方法
					MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
					//检查指定类型是否可以转换为目标对象的类型
					boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);
					//创建一个要被注入的依赖描述
					DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);
					//根据容器的Bean定义解析依赖关系,返回所有要被注入的Bean对象
					Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);
					if (autowiredArgument != null) {
						pvs.add(propertyName, autowiredArgument);
					}
					for (String autowiredBeanName : autowiredBeanNames) {
						//指定名称属性注册依赖Bean名称,进行属性依赖注入
						registerDependentBean(autowiredBeanName, beanName);
						if (logger.isTraceEnabled()) {
							logger.trace("Autowiring by type from bean name '" + beanName + "' via property '" +
									propertyName + "' to bean named '" + autowiredBeanName + "'");
						}
					}
					//释放已自动注入的属性
					autowiredBeanNames.clear();
				}
			}
			catch (BeansException ex) {
				throw new UnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);
			}
		}
	}

  可以看出来通过属性名进行自动依赖注入的相对比通过属性类型进行自动依赖注入要稍微简单一些, 但是真正实现属性注入的是DefaultSingletonBeanRegistry的registerDependentBean()方法。

  • 3、DefaultSingletonBeanRegistry 的 registerDependentBean()方法对属性注入
  • 4、autowiring小结
      通过对 autowiring 的源码分析,我们可以看出,autowiring 的实现过程:
  1. 对Bean的属性代调用getBean()方法,完成依赖Bean的初始化和依赖注入。
  2. 将依赖Bean的属性引用设置到被依赖的Bean属性上。
  3. 将依赖Bean的名称和被依赖Bean的名称存储在IOC容器的集合中。

  Spring IOC 容器的autowiring属性自动依赖注入是一个很方便的特性,可简化开发时的配置。

1.4 两种后置处理器

  Spring提供了两种后处理bean的扩展接口:BeanPostProcessor和BeanFactoryPostProcessor。
  在BeanFactory初始化之后可以使用BeanFactoryPostProcessor进⾏后置处理做一些事情;在Bean对象实例化(并不是Bean的整个生命周期完成)之后可以使用BeanPostProcessor进行后置处理做一些事情。

  • 1、BeanPostProcessor
      BeanPostProcessor是针对Bean级别的处理,可以针对某个具体的Bean。
      Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理。Bean后置处理器对IOC容器里的所有bean实例逐一处理,其典型应用是:检查Bean属性的正确性或根据特定的标准更改bean的属性。
      Bean后置处理器时需要实现BeanPostProcessor接口,需要实现的方法:
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

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

  该接口提供了两个方法,分别在Bean的初始化方法前和初始化方法后执行。
  定义1个类实现了BeanPostProcessor,默认是会对整个Spring容器中所有的bean进行处理。如果要对具体的某个bean处理,可以通过方法参数判断,两个类型参数分别为Object和String,第1个参数是每个bean的实例,第2个参数是每个bean的name或者id属性的值。所以我们可以通过第2个参数,来判断我们将要处理的具体的bean。

  具体实现:

  1. 编写一个类去实现BeanPostProcessor接口;
  2. 实现接口的两个方法;
  3. 到Spring的配置文件中去配置后置处理器。

  示例:

public class MyBeanPostProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println( " 初始化之前 obj => " + bean + " , id =>" + beanName );
        return bean;
    }

    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println( " 初始化之后 obj => " + bean + " , id =>" + beanName );

        if ("p22".equals(beanName)) {
            Person p = (Person) bean;
            p.setCar(new Car("QQ卡丁车", "京C444444"));
        }

        return bean;
    }
}

  配置示例:






  添加Bean后置处理器后Bean的生命周期:

  1. 通过构造器或工厂方法创建Bean实例;
  2. 为Bean的属性设置值和对其他Bean的引用;
  3. 将Bean实例传递给Bean后置处理器的postProcessBeforeInitialization()方法;
  4. 调用Bean的初始化方法;
  5. 将Bean实例传递给Bean后置处理器的postProcessAfterInitialization()方法;
  6. Bean可以使用了;
  7. 当容器关闭时调用Bean的销毁方法。
  • 2、BeanFactoryPostProcessor
      BeanFactory级别的处理,是针对整个Bean的工厂进行处理,此接口只提供了1个方法,方法参数为ConfigurableListableBeanFactory:
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

  ConfigurableListableBeanFactory中定义了一些方法:

  其中有个方法名为getBeanDefinition的方法,我们可以根据此方法,找到我们定义bean 的BeanDefinition对象。然后我们可以对定义的属性进行修改。BeanDefinition中的方法:

  方法名字类似我们bean标签的属性,setBeanClassName对应bean标签中的class属性,所以当我们拿到BeanDefinition对象时,我们可以手动修改bean标签中所定义的属性值。
  BeanDefinition对象:我们在 XML 中定义的 bean标签,Spring解析bean标签成为1个JavaBean,这个JavaBean就是BeanDefinition。
  注意:调用BeanFactoryPostProcessor方法时,这时候bean还没有实例化,此时bean刚被解析成BeanDefinition对象。

二、Bean生命周期的相关问题 2.1 Spring框架中Bean的生命周期 2.1.1 简述

  • 1、Spring对bean进行实例化;
  • 2、Spring将值和bean的引用注入到bean对应的属性中;
  • 3、如果bean实现了BeanNameAware接口,Spring将bean的ID传递给setBeanName()方法;
  • 4、如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory容器实例传入;
  • 5、如果bean实现了ApplicationContextAware接口,Spring将调用setApplicationContext()方法,将bean所在的应用上下文的引用传入进来;
  • 6、如果bean实现了BeanPostProcessor接口,Spring将调用它们的postProcessBeforeInitialization()方法;
  • 7、如果bean实现了InitializingBean接口,Spring将调用它们的afterPropertiesSet()方法。类似地,如果bean使用initmethod声明了初始化方法,该方法也会被调用;
  • 8、如果bean实现了BeanPostProcessor接口,Spring将调用它们的post-ProcessAfterInitialization()方法;
  • 9、此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
  • 10、如果bean实现了DisposableBean接口,Spring将调用它的destroy()接口方法。同样,如果bean使用destroy-method声明了销毁方法,该方法也会被调用。
2.1.2 详述

  Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类:
  1、Bean自身的方法:这个包括了Bean本身调用的方法和通过配置文件中的init-method和destroy-method指定的方法。
  2、Bean级生命周期接口方法:这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法
  3、容器级生命周期接口方法:这个包括了InstantiationAwareBeanPostProcessor和BeanPostProcessor这两个接口实现,一般称它们的实现类为“后处理器”。
  4、工厂后处理器接口方法:这个包括了AspectJWeavingEnabler、ConfigurationClassPostProcessor、CustomAutowireConfigurer等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。

  Spring Bean的生命周期可以主要分为如下4个部分:

  1. 处理BeanDefinition:BeanDefinition的解析,注册,合并;
  2. Bean实例化(Instantiation):还没有生成bean,即没有调用构造函数,生成对象;
  3. Bean初始化(Initialization):已经生成bean,进行属性赋值;
  4. Bean销毁:并没有gc。
  • 1、BeanDefinition解析阶段
配置方式实现类
XML资源XmlBeanDefinitionReader
Properties资源PropertiesBeanDefinitionReader
Java注解AnnotatedBeanDefinitionReader

  在Spring中,用BeanDefinition来描述一个Bean,因为Bean在对象的基础上增加了很多属性,如Bean是单例的还是原型的、Bean是否延迟加载等。
  BeanDefinition的一些元信息:

属性说明
beanClassbean对应的Class类
lazyInit是否延迟初始化
autowireMode自动绑定模式,无,byName,byType等
initMethodName初始化回调方法
destroyMethodName销毁回调方法
2.1.3 相关生命周期方法的使用

  有三种方式在Bean初始化后和销毁前添加一些操作:

  1. Bean的方法加上@PostConstruct和@PreDestroy注解(必须有component-scan才有效)。
  2. 在xml中,定义init-method和destory-method方法。
  3. Bean实现InitializingBean和DisposableBean接口。

  其执行顺序关系为:
  Bean在实例化的过程中:constructor > @PostConstruct >InitializingBean > init-method。
  Bean在销毁的过程中:@PreDestroy > DisposableBean > destroy-method。

  还可以通过BeanPostProcessor在bean初始化前后添加一些操作。
  初始化执行顺序为:constructor > BeanPostProcessor#postProcessBeforeInitialization >
@PostConstructor > InitializingBean > init-method > BeanPostProcessor#
postProcessAfterInitialization。
  调用用户自定义初始化方法之前和之后分别会调用BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法。

2.2 用xml配置的方式重写init和destroy方法

  bean生命周期表示bean的创建到销毁。

  1. 如果bean是单例,容器在启动的时候会创建好,关闭的时候会销毁bean;
  2. 如果bean是多例,获取的时候创建对象,销毁的时候不会有任何的调用。

  在创建对象的时候,可以根据需要调用初始化和销毁的方法,示例:

    
    

  在具体的实体类里即可以实现上面的两个方法,示例:

    public void init(){
        System.out.println("对象被初始化");
    }
    
    public void destory(){
        System.out.println("对象被销毁");
    }
转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号