SpringBoot IOC容器的高级特性

news/2024/10/30 14:06:42/

一、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定义资源的<Bean>元素中配置了lazy-init=false属性时,容器将会在初始化的时候对所配置的Bean进行预实例化,Bean的依赖注入在容器初始化的时候就已经完成。这样,当应用程序第一次向容器索取被管理的Bean时,就不用再初始化和对Bean进行依赖注入了,直接从容器中获取已经完成依赖注入的现成Bean,可以提高应用第一次向容器获取Bean的性能。

1.1.1 延迟加载的使用

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

  比如:

	<beanid="testBean"class="cn.lagou.LazyBean"/><!--该bean默认的设置为:--><beanid="testBean"calss="cn.lagou.LazyBean"lazy-init="false"/>

  lazy-init="false",立即加载,表示在spring启动时,立刻进行实例化。

  如果不想让个单例Bean在ApplicationContext实现初始化时被提前实例化,那么可以将Bean设置为延迟实例化。示例:

	<beanid="testBean"calss="cn.lagou.LazyBean"lazy-init="true"/>

  设置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容器。@Overridepublicvoidrefresh()throwsBeansException,IllegalStateException{synchronized(this.startupShutdownMonitor){// 调用容器准备刷新的方法,获取容器的当前时间,同时给容器设置同步标识prepareRefresh();// 获得beanFactoryConfigurableListableBeanFactory beanFactory =obtainFreshBeanFactory();// beanFactory的预准备工作,对beanfactory配置容器特性,例如类加载器、事件处理器等prepareBeanFactory(beanFactory);try{//beanFactory准备工作完成之后要进行的后置处理(BeanPost事件处理)工作,留给子类扩展使用postProcessBeanFactory(beanFactory);//调用所有注册的BeanFactoryPostProcessor的BeaninvokeBeanFactoryPostProcessors(beanFactory);//为BeanFactory注册BeanPost事件处理器//BeanPostProcessors是Bean后置处理器,用于监听容器触发的事件registerBeanPostProcessors(beanFactory);//初始化MessageSource信息源,即国际化处理、消息绑定、消息解析initMessageSource();//初始化容器事件传播器initApplicationEventMulticaster();//留给子类来初始化其他的beanonRefresh();//在所有注册的bean中查找ApplicationListener,为事件广播器注册事件监听器registerListeners();//初始化所有剩下的单实例beanfinishBeanFactoryInitialization(beanFactory);//完成刷新过程,初始化容器的生命周期事件处理器,并发布容器的生命周期事件finishRefresh();}catch(BeansException ex){if(logger.isWarnEnabled()){logger.warn("Exception encountered during context initialization - "+"cancelling refresh attempt: "+ ex);}// 销毁已经创建的BeandestroyBeans();// 取消刷新操作,重置容器的同步标识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进行实例化处理protectedvoidfinishBeanFactoryInitialization(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的预实例化

	@OverridepublicvoidpreInstantiateSingletons()throwsBeansException{if(logger.isTraceEnabled()){logger.trace("Pre-instantiating singletons in "+this);}//获取容器中的所有bean,依次进行初始化和创建对象List<String> beanNames =newArrayList<>(this.beanDefinitionNames);for(String beanName : beanNames){//获取bean的定义信息RootBeanDefinition bd =getMergedLocalBeanDefinition(beanName);//bean不是抽象的、是单实例的、是懒加载的if(!bd.isAbstract()&& bd.isSingleton()&&!bd.isLazyInit()){//判断是否是FactoryBean,是否是实现FactoryBean接口的beanif(isFactoryBean(beanName)){Object bean =getBean(FACTORY_BEAN_PREFIX + beanName);if(bean instanceofFactoryBean){finalFactoryBean<?> factory =(FactoryBean<?>) bean;//标识是否需要实例化boolean isEagerInit;if(System.getSecurityManager()!=null&& factory instanceofSmartFactoryBean){isEagerInit =AccessController.doPrivileged((PrivilegedAction<Boolean>)((SmartFactoryBean<?>) factory)::isEagerInit,getAccessControlContext());}else{isEagerInit =(factory instanceofSmartFactoryBean&&((SmartFactoryBean<?>) factory).isEagerInit());}if(isEagerInit){getBean(beanName);}}}else{//不是工厂Bean,利用getBean创建对象getBean(beanName);}}}for(String beanName : beanNames){Object singletonInstance =getSingleton(beanName);if(singletonInstance instanceofSmartInitializingSingleton){finalSmartInitializingSingleton smartSingleton =(SmartInitializingSingleton) singletonInstance;if(System.getSecurityManager()!=null){AccessController.doPrivileged((PrivilegedAction<Object>)()->{smartSingleton.afterSingletonsInstantiated();returnnull;},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,用于产生其他对象 publicinterfaceFactoryBean<T>{//获取容器管理的对象实例 @NullableTgetObject()throwsException;//获取 Bean 工厂创建的对象的类型 @NullableClass<?>getObjectType();//Bean 工厂创建的对象是否是单态模式,如果是单态模式,则整个容器中只有一个实例 //对象,每次请求都返回同一个实例对象 defaultbooleanisSingleton(){returntrue;}}
  • 2、AbstractBeanFactory的getBean()方法调用FactoryBean
      在前面我们分析Spring IOC容器实例化Bean并进行依赖注入过程的源码时,提到在getBean()方法触发容器实例化Bean的时候会调用AbstractBeanFactory的doGetBean()方法来进行实例化的过程:

	//真正实现向IOC容器获取Bean的功能,也是触发依赖注入功能的地方@SuppressWarnings("unchecked")protected<T>TdoGetBean(finalString name,@NullablefinalClass<T> requiredType,@NullablefinalObject[] args,boolean typeCheckOnly)throwsBeansException{//根据指定的名称获取被管理的Bean的名称//如果指定的是别名,将别名转换为规范的Bean名称finalString beanName =transformedBeanName(name);Object bean;//直接尝试从缓存获取是否已经有被创建过的单例的BeanObject 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)){thrownewBeanCurrentlyInCreationException(beanName);}//对IOC容器中是否存在指定名称的BeanDefinition进行检查,首先检查是否能在//当前的BeanFactory中获取所需要的Bean。如果不能再委托当前容器的父容器去//查找,如果还是找不到则沿着继承关系继续查找BeanFactory parentBeanFactory =getParentBeanFactory();//当前容器的父容器存在,且当前容器中不存在指定名称的Beanif(parentBeanFactory !=null&&!containsBeanDefinition(beanName)){//解析指定Bean名称的原始名称String nameToLookup =originalBeanName(name);if(parentBeanFactory instanceofAbstractBeanFactory){return((AbstractBeanFactory) parentBeanFactory).doGetBean(nameToLookup, requiredType, args, typeCheckOnly);}//递归到beanFactory中寻找elseif(args !=null){//委派父容器根据指定名称和显式的参数查找return(T) parentBeanFactory.getBean(nameToLookup, args);}elseif(requiredType !=null){//委派父容器根据指定名称和类型查找return parentBeanFactory.getBean(nameToLookup, requiredType);}else{//委派父容器根据指定名称查找return(T) parentBeanFactory.getBean(nameToLookup);}}//创建的Bean是否需要进行类型验证if(!typeCheckOnly){//向容器标记指定的Bean已经被创建markBeanAsCreated(beanName);}try{//根据指定Bean名称获取其父级Bean定义,主要解决Bean继承时子类和父类公共属性问题finalRootBeanDefinition 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)){thrownewBeanCreationException(mbd.getResourceDescription(), beanName,"Circular depends-on relationship between '"+ beanName +"' and '"+ dep +"'");}//把能依赖Bean注册给当前依赖的BeanregisterDependentBean(dep, beanName);try{//递归调用,获取BeangetBean(dep);}catch(NoSuchBeanDefinitionException ex){thrownewBeanCreationException(mbd.getResourceDescription(), beanName,"'"+ beanName +"' depends on missing bean '"+ dep +"'", ex);}}}//创建单例模式的Bean的实例对象if(mbd.isSingleton()){//调用匿名内部类创建Bean实例对象sharedInstance =getSingleton(beanName,()->{try{returncreateBean(beanName, mbd, args);}catch(BeansException ex){//从单例模式的Bean缓存中清除实例对象destroySingleton(beanName);throw ex;}});//获取给定Bean的实力对象bean =getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}//IOC容器创建原型模式的Bean实例对象elseif(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既不是单例模式也不是原型模式,创建其他生命周期的BeanString scopeName = mbd.getScope();finalScope scope =this.scopes.get(scopeName);//如果Bean定义资源中没有配置生命周期范围,则Bean定义不合法if(scope ==null){thrownewIllegalStateException("No Scope registered for scope name '"+ scopeName +"'");}try{//调用匿名内部类,获取一个指定生命周期范围的实例Object scopedInstance = scope.get(beanName,()->{beforePrototypeCreation(beanName);try{returncreateBean(beanName, mbd, args);}finally{afterPrototypeCreation(beanName);}});//获取指定Bean的实例对象bean =getObjectForBeanInstance(scopedInstance, name, beanName, mbd);}catch(IllegalStateException ex){thrownewBeanCreationException(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){thrownewBeanNotOfRequiredTypeException(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);}thrownewBeanNotOfRequiredTypeException(name, requiredType, bean.getClass());}}return(T) bean;}protectedObjectgetObjectForBeanInstance(Object beanInstance,String name,String beanName,@NullableRootBeanDefinition mbd){// Don't let calling code try to dereference the factory if the bean isn't a factory.if(BeanFactoryUtils.isFactoryDereference(name)){if(beanInstance instanceofNullBean){return beanInstance;}if(!(beanInstance instanceofFactoryBean)){thrownewBeanIsNotAFactoryException(beanName, beanInstance.getClass());}}if(!(beanInstance instanceofFactoryBean)||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实例对象protectedObjectgetObjectFromFactoryBean(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){thrownewBeanCreationException(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){thrownewBeanCreationException(beanName,"Post-processing of FactoryBean's object failed", ex);}}return object;}}//调用Bean工厂的getObject方法生产指定Bean的实例对象privateObjectdoGetObjectFromFactoryBean(finalFactoryBean<?> factory,finalString beanName)throwsBeanCreationException{Object object;try{if(System.getSecurityManager()!=null){AccessControlContext acc =getAccessControlContext();try{//实现PrivilegedExceptionAction接口的匿名内部类//根据JVM检查权限,然后决定BeanFactory创建实例对象object =AccessController.doPrivileged((PrivilegedExceptionAction<Object>) factory::getObject, acc);}catch(PrivilegedActionException pae){throw pae.getException();}}else{//直接调用getobject方法创建对象object = factory.getObject();}}catch(FactoryBeanNotInitializedException ex){thrownewBeanCurrentlyInCreationException(beanName, ex.toString());}catch(Throwable ex){thrownewBeanCreationException(beanName,"FactoryBean threw exception on object creation", ex);}//创建出来的对象实例为null,或者因为单例对象正在创建而返回nullif(object ==null){if(isSingletonCurrentlyInCreation(beanName)){thrownewBeanCurrentlyInCreationException(beanName,"FactoryBean which is currently in creation returned null from getObject");}object =newNullBean();}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自动依赖注入

	//根据类型对属性进行自动依赖注入protectedvoidautowireByType(String beanName,AbstractBeanDefinition mbd,BeanWrapper bw,MutablePropertyValues pvs){//获取用户定义的类型转化器TypeConverter converter =getCustomTypeConverter();if(converter ==null){converter = bw;}//存放解析的要注入的属性Set<String> autowiredBeanNames =newLinkedHashSet<>(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()instanceofPriorityOrdered);//创建一个要被注入的依赖描述DependencyDescriptor desc =newAutowireByTypeDependencyDescriptor(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){thrownewUnsatisfiedDependencyException(mbd.getResourceDescription(), beanName, propertyName, ex);}}}

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

  • 3、DefaultSingletonBeanRegistry的registerDependentBean()方法对属性注入

  • 4、autowiring小结
      通过对 autowiring 的源码分析,我们可以看出,autowiring 的实现过程:

对Bean的属性代调用getBean()方法,完成依赖Bean的初始化和依赖注入。
将依赖Bean的属性引用设置到被依赖的Bean属性上。
将依赖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接口,需要实现的方法:

	@NullabledefaultObjectpostProcessBeforeInitialization(Object bean,String beanName)throwsBeansException{return bean;}@NullabledefaultObjectpostProcessAfterInitialization(Object bean,String beanName)throwsBeansException{return bean;}

  该接口提供了两个方法,分别在Bean的初始化方法前和初始化方法后执行。

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

  具体实现:

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

  示例:

publicclassMyBeanPostProcessorimplementsBeanPostProcessor{/*** 在初始化方法之前执行,做一些操作* @param bean  当前初始化的对象实例* @param beanName  当前初始化对象的id值* @return 返回值是当前初始化对象( 它会替代当前初始化对象 )*/@OverridepublicObjectpostProcessBeforeInitialization(Object bean,String beanName)throwsBeansException{System.out.println(" 初始化之前 obj => "+ bean +" , id =>"+ beanName );return bean;}/*** 在初始化方法之后执行,做一些操作* @param bean  当前初始化的对象实例* @param beanName  当前初始化对象的id值*/@OverridepublicObjectpostProcessAfterInitialization(Object bean,String beanName)throwsBeansException{System.out.println(" 初始化之后 obj => "+ bean +" , id =>"+ beanName );if("p22".equals(beanName)){Person p =(Person) bean;p.setCar(newCar("QQ卡丁车","京C444444"));}return bean;}}

  配置示例:

<!--init-method 是初始化方法 ( 在Bean对象创建之后马上调用 )destroy-method 是销毁方法 ( 在Spring容器关闭的时候调用 , 只对单例有效 )
--><beanclass="com.spring.test.Person"id="p22"scope="prototype"init-method="init"destroy-method="destroy"></bean><!-- 配置后置处理器 --><beanclass="com.spring.test.MyBeanPostProcessor"/>

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

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

	voidpostProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throwsBeansException;

  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本身调用的方法和通过配置文件中<bean>的init-method和destroy-method指定的方法。

  2、Bean级生命周期接口方法:这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法

  3、容器级生命周期接口方法:这个包括了InstantiationAwareBeanPostProcessor和BeanPostProcessor这两个接口实现,一般称它们的实现类为“后处理器”。

  4、工厂后处理器接口方法:这个包括了AspectJWeavingEnabler、ConfigurationClassPostProcessor、CustomAutowireConfigurer等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。

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

处理BeanDefinition:BeanDefinition的解析,注册,合并;
Bean实例化(Instantiation):还没有生成bean,即没有调用构造函数,生成对象;
Bean初始化(Initialization):已经生成bean,进行属性赋值;
Bean销毁:并没有gc。
  • 1、BeanDefinition解析阶段

配置方式

实现类

XML资源

XmlBeanDefinitionReader

Properties资源

PropertiesBeanDefinitionReader

Java注解

AnnotatedBeanDefinitionReader

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

  BeanDefinition的一些元信息:

属性

说明

beanClass

bean对应的Class类

lazyInit

是否延迟初始化

autowireMode

自动绑定模式,无,byName,byType等

initMethodName

初始化回调方法

destroyMethodName

销毁回调方法

2.1.3 相关生命周期方法的使用

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

Bean的方法加上@PostConstruct和@PreDestroy注解(必须有component-scan才有效)。
在xml中,定义init-method和destory-method方法。
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的创建到销毁。

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

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

<beanid="getUser"class="com.test.bean.User" init-method="init"destroy-method="destory"></bean>

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

publicvoidinit(){System.out.println("对象被初始化");}publicvoiddestory(){System.out.println("对象被销毁");}

http://www.ppmy.cn/news/32563.html

相关文章

ChatGPT-4 终于来了(文末附免费体验地址)

大家好&#xff0c;我是小钱学长。 ChatGPT4.0 重磅来袭&#xff0c;今天一打开plus页面出现的就是这个GPT-4的体验界面&#xff01;现在就带大家一起看看GPT4.0​。 进入之后是这样的 看到最下面有一行话&#xff0c;目前应该是4个小时限制100条消息。 GPT-4有什么优势&…

Linux/Debian/Ubuntu-OpenCV(4.5.4/4.6.0)+CUDA(11.3)配置编译全流程

文章目录前言相关资源下载OpenCVCUDA下载CUDNN下载编译错误异常前言 本文用来记录在linux环境下docker中编译OpenCV with cuda的过程&#xff0c;同时编译了4.5.4和4.6.0两个版本均可编译通过。 本地是linux环境也可参考本文完成编译。 系统&#xff1a;debian 11 CPU&#…

【码字必看】一篇文章带你轻松上手MarkDown

文章目录&#x1f36c;前言&#x1f62e;什么是MarkDown&#x1f9d0;为什么要学习MarkDown&#x1f511;使用MarkDown的工具&#x1f4da;MarkDown基础语法&#x1f95d;标题&#x1f965;字体&#xff08;斜体、粗体、粗斜体&#xff09;&#x1f347;各种线&#xff08;分割…

【动态规划】不同路径,编辑距离题解及代码实现

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…

SpringBoot整合RabbitMQ,包含:初始化定义队列,消息发送,消息接收 --柚子真好吃

一、搭建RabbitMq服务并创建账号 服务采用Docker临时搭建&#xff0c;版本采用3.8&#xff0c;命令如下 拉取镜像 docker pull rabbitmq:3.8.34-management创建容器 由于我使用的是 Docker Desktop 可通过可视化界面创建容器&#xff0c;将端口对应好即可&#xff0c;如下图&…

Opencv项目实战:22 物体颜色识别并框选

目录 0、项目介绍 1、效果展示 2、项目搭建 3、项目代码展示与部分讲解 Color_trackbar.py bgr_detector.py test.py 4、项目资源 5、项目总结 0、项目介绍 本次项目要完成的是对物体颜色的识别并框选&#xff0c;有如下功能&#xff1a; &#xff08;1&#xff09;…

JavaWeb学习-JSP

JSP作用 JSP全称为Java Server Pages即Java服务器页面&#xff0c;主要作用是代替Servlet程序回传HTML页面的数据&#xff0c;因为Servlet程序回传HTML页面数据非常繁琐&#xff0c;开发成本和维护成本较高。 package com.pero.jsp.jsp_javaweb;import jakarta.servlet.*; im…

C++模拟实现红黑树

目录 介绍----什么是红黑树 甲鱼的臀部----规定 分析思考 绘图解析代码实现 节点部分 插入部分分步解析 ●父亲在祖父的左&#xff0c;叔叔在祖父的右&#xff1a; ●父亲在祖父的右&#xff0c;叔叔在祖父的左&#xff1a; 测试部分 整体代码 介绍----什么是红黑树 红…