Spring基本用法(三)

一、Spring中bean实例的创建方式

    ①调用构造器创建Bean实例

       大多数情况下,BeanFactory直接通过new关键字调用构造器来创建Bean实例,而class属性指定了Bean实例的实现类。Spring对Bean实例的所有属性执行默认初始化,即所有基本类型的值初始化为0或false,所有引用类型的值初始化为null,接下来,BeanFactory会根据配置文件决定依赖关系,先实例化被依赖的Bean实例,然后为Bean注入依赖关系,最后将一个完整的Bean实例返回给程序。

    ②使用静态工厂方法创建Bean

        使用静态工厂方法创建Bean实例时,class属性也必须指定,但此时class属性并不是指定Bean实例的实现类,而是静态工厂类。Spring需要知道由哪个静态工厂方法来创建Bean实例

       class:该属性的值为静态工厂类的类名

       factory-method:该属性指定生产Bean实例的静态工厂方法,如果方法需要参数,则使用<constructor-arg.../>元素传入

       当我们指定Spring使用静态工厂方法来创建Bean实例时,Spring将先解析配置文件,并根据配置文件指定的信息,通过反射调用静态工厂类的静态工厂方法,将该静态工厂方法的返回值作为Bean实例。在这个过程中,Spring不再负责创建Bean实例,Bean实例时由用户提供的静态工厂类负责创建的。当实例被建成后,Spring依然可以管理该Bean实例的依赖关闭,包括为其注入所需的依赖关系、管理其生命周期等。

     ③调用实例工厂方法创建Bean

         实例工厂方法与静态工厂方法只有一点不同:调用静态工厂方法只需使用工厂类即可,调用实例工厂方法则必须使用工厂实例。

       factory-bean:该属性的值为工厂Bean的id

       factor-method:该属性指定实例工厂的工厂方法,如果方法需要参数,则使用<constructor-arg.../>元素传入

 二、深入理解容器中的Bean

      ①抽象Bean和子Bean

        抽象Bean和一般Bean没有区别,只是在配置文件中指定abstract=“true”,当程序采用ApplicationContext作为Spring容器,程序实例化ApplicationContext容器时会默认实例化singleton Bean,但不会初始化abstract=true的Bean

        通过给一个元素指定parent属性即可指定该Bean是一个子Bean,parent属性指定该Bean所继承的父Bean的id。子Bean可以从父Bean定义继承实现类、依赖关系等配置信息,子Bean也可覆盖父Bean的配置信息

        此处的Bean继承与Java中通俗的继承有区别:①Spring中Bean继承只是实例之间的关系,主要表现为参数值的延续,而Java中的继承是类之间的关系,主要表现为方法、属性的延续②Spring中的子Bean不可作为父Bean使用,不具备多态性,Java中的子类实例完全可当成父类实例使用③Spring中的子Bean和父Bean可以是不同类型,但Java中的继承则可保证子类是一种特殊父类

       注意:被标注成abstract=true的类并不一定要真的是abstract类,这种抽象bean和子bean主要用于,当系统中bean增多,并且大部分bean的配置信息相同时,可定义一个抽象的模板类,把这些共同的配置信息写在模板类中,然后让其他的bean继承此模板bean即可

     ②容器中的工厂Bean

        此处的工厂Bean与前面介绍的实例工厂方法创建Bean或静态工厂方法创建Bean的工厂有所区别:前面那些工厂是标准的工厂模式,Spring只是负责调用工厂方法来创建Bean实例;此处的工厂Bean是Spring的一种特殊Bean,这种工厂Bean必须实现FactoryBean接口。

        FactoryBean接口是工厂Bean的标准接口,实现该接口的Bean通常只能作为工厂Bean使用,当我们将工厂Bean部署在容器中,并通过getBean()方法来获取工厂Bean时,容器不会返回FactoryBean实例,而是返回FactoryBean的产品

        FactoryBean接口提供如下三个方法:

         →T getObject():实现该方法负责返回该工厂Bean生成的Java实例。

         →Class<?>getObjectType():实现该方法返回该工厂Bean生成的Java实例的实现类

         →boolean isSingleton():实现该方法表示该工厂Bean生成的Java实例是否为单例模式

         部署工厂Bean与部署普通Bean其实没有任何区别,只是通过id获取的不是工厂Bean,而是工厂Bean产生的产品Bean。

          FactoryBean是Spring中非常有用的一个接口,Spring内置提供了很多实用的工厂Bean,例如TransactionProxyFactoryBean等,这个工厂Bean专门用于为目标Bean创建事物代理

        ③获取bean本身id

         前面我们接触到的都是通过id得到Bean实例,而有时候我们知道Bean实例却不知道它的id,要想得到id可以让Bean实现接口BeanNameAware,通过实现方法setBeanName(由Spring容器自己调用)得到id

        ④强制化初始Bean

         Spring默认有个规则,总是先初始化要被注入的Bean,再初始化要实例化的Bean,可以通过设置depends-on强制指定先初始化哪个Bean

三、容器中bean的生命周期

       对于singleton作用域的Bean,Spring容器知道Bean何时实例化结束、何时销毁,Spring可以管理实例化结束之后和销毁之前的行为。管理Bean的生命周期行为主要有如下两个时机:

       ①注入依赖关系之后

          Spring提供两种方式在Bean全部属性设置成功后执行特定行为:使用init-method属性(推荐,代码污染小);实现InitializingBean接口(实现接口方法afterPropertiesSet() throws Exception),如果两种方式都使用的话,容器在设置完属性后,先执行InitializingBean接口中定义的方法,然后执行init-method属性指定的方法。

       ②即将销毁Bean之前

          Spring提供两种方法定制Bean实例销毁之前的特定行为,:使用destroy-method属性(推荐,代码污染小);实现DisposableBean接口(实现接口方法destroy() throws Exception),如果两种方法都使用,容器在实例销毁之前,先执行DisposableBean接口中定义的方法,然后执行destroy-method属性指定的方法。

       singleton作用域的Bean通常会随容器的关闭而销毁,但问题是:ApplicationContext容器在什么时候关闭呢?在基于Web的ApplicationContext实现中,系统已经提供了相应的代码保证关闭Web应用时恰当地关闭Spring容器;如果处于一个非Web应用的环境下,为了让Spring容器优雅地关闭,并调用singleton Bean上的相应析构回调方法

      如果容器中很多bean都需要指定生命周期方法,则可利用<beans../>元素的default-init-method属性和default-destroy-method属性

 需要指出的是,当Bean实现了ApplicationContextAware接口、BeanNameAware接口之后,Spring容器会在该Bean初始化完成之后--也就是调用init-method属性所指定的方法(如果有)之后,再来回调setApplicationContext(ApplicationContext applicationContext)、setBeanName(String name)方法

       由于singleton Bean具有单例行为,当客户端多次请求singleton Bean时,Spring返回给客户端的将是同一个singleton Bean实例,这不存在任何问题。问题是:如果客户端多次请求singleton Bean、并调用该singleton Bean去调用prototype Bean的方法时-----始终都是调用同一个prototype Bean实例,这就违背了设置prototype Bean的初衷:本来希望它具有prototype行为,但实际上它却表现出singleton行为了。

       解决这种不同步问题有如下两种思路:

       →部分放弃依赖注入:singleton作用域Bean每次需要prototype作用域Bean时,主动向容器请求新的Bean实例,即可保证每次注入的prototype Bean实例都是最新的实例(代码污染)

       →利用方法注入(使用lookup),利用lookup方法注入可以让Spring容器重写容器中Bean的抽象或具体方法,返回查找容器中其他Bean的结果,被查找的Bean通常是一个non-singletong Bean(尽管也可以是一个singleton的)。

        例:在要依赖prototype Bean的singleton Bean中定义个abstract get方法,然后在配置文件中<lookup-method name="get" bean="prototypeBeanid"/>

四、深入理解依赖关系配置

       Spring不仅支持普通的值注入和依赖于其他已知Bean的注入,还支持将Bean实例的属性值、方法返回值、Field值直接定义成容器中的一个变量

      ①注入其他Bean的属性值   使用PropertyPathFactoryBean,例<bean id="person.son.age“ class="org.springframework.beans.factory.config.PropertyPathFactoryBean"/>这种配置方式下的id不是该Bean的唯一标识,而是指定属性表达式值

     ②注入其他Bean的Field 使用FieldRetrievingFactoryBean,例<bean id="java.sql.Connection.TRANSACTION_SERIALIZABLE“ class="org.springframework.beans.factory.config.FieldRetrievingFactoryBean"/>,field既可以是静态的也可以是动态的(对应targetObject)

      ③注入其他Bean的方法返回值 使用MethodInvokingFactoryBean  例<bean id="sysProps“ class="org.springframework.beans.factory.config.MethodInvokingFactoryBean  "><property name="targetClass" value="java.lang.System"/><property name="targetMethod" value="getProperties"/></bean> method既可以是静态方法,也可以是非静态的(对应targetObject)

      

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值