`
足至迹留
  • 浏览: 495772 次
  • 性别: Icon_minigender_1
  • 来自: OnePiece
社区版块
存档分类
最新评论

<3> 高级bean装配

阅读更多
相对上篇,这次内容有些不太常用,但有些还是非常有用,不能忽略。掌握之后对理解spring的源码也很有好处。

一、父bean和子bean

bean也可以继承,为此spring提供了两个属性:
parent: 指明bean的id.它对于<bean>的作用就相当于java关键字extends(但功能又有所不同,后面会看到子bean可以和父bean具有不同的class类型).
abstract: 如果设置为true,就表示<bean>是抽象的,不能被实例化,一般作为父bean.但父bean不一定就是抽象的。

通过使用parent属性可以指定父bean,子bean可以从父bean继承<property>和class属性,无法继承depends-on, autowire, dependency-check, singleton, scope, lazy-init等属性。
如:
<bean id=”fatherBean” class=”com.Instrumentalist” abstract=”true”>
<property name=”instrument” ref=”saxophone” />
<property name=”song” value=”jingle bells” />
</bean>
作为父bean,abstract=”true”不是必须的,这里只是说这个bean不能实例化,只提供公共属性。
<bean id=”kenny” parent=”fatherBean” />
<bean id=”david” parent=”fatherBean” />
这两个子bean都继承了父bean的属性。同时,子bean还可以覆盖父bean的属性,如:
<bean id=”david” parent=”fatherBean” >
    <property name=”song” value=”young” />   ------这里就覆盖了song属性。
</bean>

Sping里,子bean还可以不必具有相同的父类型,两个class属性不同的bean仍然可以从一个父bean继承一组相同的属性。
如:
<bean id=”fatherBean” abstract=”true” >
<property name=”song” value=”rainbow” />
</bean>

<bean id=”taylor” class=”com.spring.Vocalist” parent=”fatherBean” />
<bean id=”stevie” class=”com.spring.Instrument” parent=”fatherBean” />
这两个子bean具有不同的class类型,只是继承了父类共同的属性。

二、Bean的方法注入
上一篇介绍了bean的常用注入方式,setter和constructor方式,这里介绍下第三种注入方式,方法注入。上一篇中提到了factory-method使用静态方法注入bean,下面介绍下静态工厂方法注入,实例工厂方法注入和Spring支持的另外两种形式的方法注入:
方法替换: 可以在运行时用新的实现替换现有方法(抽象或具体的)。
获取器注入:可以在运行时用新的实现替换现有方法(抽象或具体的),从spring上下文返回特定的bean。
1) 静态工厂方法注入(factory-method)
•  <bean id="foo" class="...Foo"> 
•      <property name="barInterface"> 
•          <ref bean="bar"/> 
•      </property> 
•  </bean> 
•  
•  <bean id="bar" class="...StaticBarInterfaceFactory" factory-method="getInstance"/>
对于bar这个bean, class指定静态方法工厂类,factory-method指定工厂方法名称,必须是static的,然后容器调用该静态方法工厂类的指定工厂方法(getInstance),并返回方法调用后的结果,即BarInterfaceImpl的实例。也就是说,为foo注入的 bar实际上是BarInterfaceImpl的实例,即方法调用后的结果,而不是静态工厂方法类 (StaticBarInterfaceFactory)。我们可以实现自己的静态工厂方法类返回任意类型的对象实例,但工厂方法类的类型与工厂方法返回 的类型没有必然的相同关系。
某些时候,有的工厂类的工厂方法可能需要参数来返回相应实例,而不一定非要像我们的getInstance()这样没有任何参数。对于这种情况,可以通过<constructor-arg>来指定工厂方法需要的参数
•  <bean id="bar" class="...StaticBarInterfaceFactory"  factory-method="getInstance"> 
•         <constructor-arg> 
•               <ref bean="foobar"/> 
•         </constructor-arg> 
•  </bean> 
•  
•  <bean id="foobar" class="...FooBar"/>
唯一需要注意的就是,针对静态工厂方法实现类的bean定义,使用<constructor-arg>传入的是工厂方法的参数,而不是静态工厂方法实现类的构造方法的参数。
还可以参考:http://book.51cto.com/art/200908/147087.htm

2) 非静态工厂方法注入(factory-bean)
<bean id="foo" class="...Foo"> 
     <property name="barInterface"> 
           <ref bean="bar"/> 
      </property> 
</bean> 

<bean id="barFactory" class="...NonStaticBarInterfaceFactory"/>  
<bean id="bar" factory-bean="barFactory"  factory-method="getInstance"/>
NonStaticBarInterfaceFactory是作为正常的bean注册到容器的,而bar的定义则与静态工厂方法的定义有些不同。现在使用factory-bean属性来指定工厂方法所在的工厂类实例,而不是通过class属性来指定工厂方法所在类的类型。指定工厂方法名则相同,都是通过factory-method属性进行的,有了factory-bean指定的实例工厂类,这里factory-method指定的工厂方法就不需要一定是static的了。
如果非静态工厂方法调用时也需要提供参数的话,处理方式是与静态的工厂方法相似的,都可以通过<constructor-arg>来指定方法调用参数。
还可以参考:http://book.51cto.com/art/200908/147088.htm

3)方法替换(replaced-method)
<bean id=”magicBox” class=”com.MagicBoxImpl”>
<replaced-method name=”getContents” replacer=”tigerReplacer” />
</bean>
<bean id=”tigerReplacer” class=”com.TigerReplacer” />
本例中replaced-method的name属性指定magicBox的getContents()方法将被替换,替换成tigerReplacer的reimplement方法。tigerReplacer实现了spring的MethodReplacer接口,需要实现此接口的reimplement方法。

4) 获取器注入(lookup-method)
Spring利用<lookup-method>配置元素来实现获取器注入。
<bean id=”stevie” class=”com.spring.Instrumentalist”>
<lookup-method name=”getInstrument” bean=”guitar” />
</bean>
<bean id=”guitar” class=”com.Guitar” />
<lookup-method>的name属性指明了Instrumentalist的getInstrument()方法要被替换,bean=”guitar”指明getInstrument()方法替换后会返回bean(id=”guitar”)。任何返回值不是void的方法都可以被替换掉。
这个是利用cglib实现的,
可以参考:http://www.360doc.com/content/07/0327/13/18042_416051.shtml

当<bean id=”guitar” class=”com.Guitar” scope=”prototype” />bean是原型作用域时,lookup-mehtod替换掉的方法返回值每次获取的都是不同的guitar。这一点很有用,当singleton的bean依赖非singleton的bean时,用普通的注入方式则只会注入一次,每次获取的非singleton类型的bean也都一样了,这时用lookup-mehtod方法注入就对了。

5) factorybean(注意跟上面的标签<factory-bean>不是同一个概念)
Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean。工厂Bean跟普通Bean不同,其返回的对象不是指定类的一个实例,其返回的是该工厂Bean的getObject方法所返回的对象。在Spring框架内部,AOP相关的功能及事务处理中,很多地方使用到工厂Bean。
所谓FactoryBean就是指实现了spring的org.springframework.beans.factory.FactoryBean接口的bean类。配置该bean时跟普通bean一样,没有任何不同。
当配置文件中<bean>的class属性配置的实现类是FactoryBean时,通过getBean方法返回的不是FactoryBean本身,而是FactoryBean#getObject()方法所返回的对象,相当于FactoryBean#getObject()代理了getBean()方法。这样就可以实现自定义功能的bean了,比如把一个特殊字符串解析并注入到一个对象属性里。
还可以参考:http://wenku.baidu.com/view/ad5b414ef7ec4afe04a1dfa7.html


三、 注入非sping创建的bean(使用@Configurable),省略不记录了。

四、注册自定义属性编辑器
举个普通的例子
<bean id=”aa” class=”…”>
  <constructor-arg type=”int” value=”15” />
  <constructor-arg type=”java.lang.String” value=”15” />
</bean>
这里两个属性值都是15,类型一个是int,一个是String,即使不指明type(如果bean的构造函数唯一),spring也会自动解析正确类型。但还有些复杂类型spring也能自动解析,比如java.net.URL。可以直接配置:
<property name=”wsdlDocUrl” value=http://www.service.wsdl />
这是因为spring内部实现了一些类,这些类实现了java自带的java.beans.ProperyEditor接口。Java.beans.PropertyEditorSupport类是java自己提供的实现了该接口的类,我们自己(包括spring也是)直接继承PropertyEditorSupport类(根据需要重写setAsText或getAsText方法,一般给属性注入值只需要重写setAsText方法)就可以实现一些自己的属性编辑器类,然后注册到spring,这样就可以提供一些自动解析复杂对象的功能了。



Spring提供了几个自定义属性编辑器:




自定义属性编辑器的步骤:
1. 继承PropertyEditorSupport类,根据需要重写setAsText或getAsText方法/
2. 注册到spring中。使用CustomEditorConfigurer注册,这是一个BeanFactoryPostProcessor。
还可以参考:
http://www.cnblogs.com/rollenholt/archive/2012/12/27/2835191.html
这个里面用到了spring自带的属性编辑器
org.springframework.beans.propertyeditors.CustomDateEditor。
http://blog.chinaunix.net/uid-21227800-id-65926.html
这个里面可以参考写出自己的属性编辑器。

注:自定义属性编辑器和factorybean有类似的功能,都可以以灵活的方式给bean注入复杂属性,但又有区别,这个可以根据实际使用场景决定使用哪个。
还可以参考:http://blog.csdn.net/intlgj/article/details/5662399


五、使用spring的特殊bean

有些特殊的bean被当作spring框架本身的一部分,可以:
  @通过对bean配置的后处理来介入bean的创建和bean工厂的生命周期。
  @从外部属性文件加载配置信息。
  @从属性文件加载文本信息,包括国际化的消息。
  @监听和响应由其他bean和spring容器本身发布的程序事件。
  @知道它们在spring容器里的身份。

1. 后处理bean
在第二篇《基本bean配置》里有bean的生命周期图,图中可以看到spring提供了两个机会让我们可以介入bean的生命周期(这两个机会是调用BeanPostProcessor的预初始化方法和后初始化方法。),查看或改变它的配置,这杯成为“后处理”。所谓后处理就是bean的创建和装配之后来修改。BeanPostProcessor接口为我们提供了这两个机会。



postProcessBeforeInitialization()方法是在bean初始化之前被调用(即InitializingBean的afterPropertiesSet()方法和bean的自定义init-method)之前被调用的。类似的,postProcessAfterinitialization()方法是在初始化之后立即被调用的。

实现步骤:
1) 自定义类实现BeanPostProcessor接口,实现该接口的两个方法。
2) 如果bean是在BeanFactory中,则需要编写代码,使用工厂的addBeanPostProcessor注册每个BeanPostProcessor.
        如果是使用的上下文ApplicationContext,则只需要在容器里把自定义类定义为一个普通bean就可以了,容器会自动识别。这也是第一篇导读里说的ApplicationContext的更多的强大功能。
Spring框架在私下使用了BeanPostProcessor的多个实现,比如
ApplicationContextAwareProcessor就是一个BeanPostProcessor.

2. bean工厂的后处理
bean被加载后,当BeanPostProcessor对它进行后处理时,BeanFactoryPostProcessor(只能是针对上下文容器,不能是beanFactory容器)对整个spring容器进行后处理。



在全部bean定义被加载后(加载,是在实例化之前的步骤),在任何一个bean被实例化之前,spring容器会调用postProcessBeanFactory()方法。
前面出现过的自定义编辑器CustomEditorConfigurer就是BeanFactoryPostProcessor的一个实现。
BeanFactoryPostProcessor另一个很有用的实现是PropertyPlaceholderConfigurer,它从一个或多个外部属性文件(.properties文件)加载属性,还可以填充bean装配文件里的占位变量(如:${url}).
注:所有相关BeanFactoryPostProcessor的应用都只能在上下文容器(ApplicationContext,不是BeanFactory)中使用。
如:



可以配置成:
<bean id=”propertyConfigurer”
class=”org.springframework.beans.factory.config.PropertyPlaceholderConfigurer”>
<property name=”location” value=”jdbc.properties” />
</bean>
Location属性告诉spring到哪寻找属性文件。如果指定多个文件还可以使用:
<property name=”locations”>
<list>
    <value> jdbc.properties</value>
    <value> security.properties</value>
</list>
</property>
本例中,jdbc.properties包含下面信息:
Database.url=jdbc:hsqldb:Training
Datebase.driver=org.hsqldb.jdbcDriver
Database.user=appUser
Database.password=password
现在就可以定义dataSource了:



这样就可以不用硬编码了。

注:除了可以向上面那样指定属性文件,还可以使用Spring 2.5引进Context命名空间, 可以通过context:property-placeholder元素进行配置。
可以参考:http://www.2cto.com/kf/201211/167827.html


3. 国际化信息支持
可以通过spring提供的MessageSource接口实现国际化信息。Spring提供了默认的MessageSource实现,ResourceBundleMessageSource等。
这里不详细记录了,后面有问题时再详细研究。
可参考:
http://beastiedog.blog.163.com/blog/static/23984625200642224329415/
http://hi.baidu.com/iduany/item/d52245ab11021611a9cfb771
http://blog.csdn.net/xiongyayun428/article/details/7063835
http://blog.csdn.net/xiongyayun428/article/details/7062772

4. 发布事件和监听事件
依赖注入是Spring提高程序对象之间松耦合的主要手段,但并不唯一。对象之间交互的另一种方式是发布和监听程序事件。
在spring里,容器中的任何bean都可以作为事件监听者或发布者或两者都是。
1) 创建事件,只需要实现ApplicationEvent类。
2) 发布事件,利用ApplicationContext(这就要求bean能获取到上下文,后面会讲怎么获取)接口的publishEvent()方法可以发布ApplicationEvents。
除了bean要发布的事件,spring容器本身就会发布一些事件,比如:
ContextCloseEvent:程序上下文关闭事件。
ContextRefreshedEvent:程序上下文被初始化或刷新事件。
RequestHandleEvent:当一个请求被处理时,在web上下文里发布。
3) 创建监听器,只需要实现ApplicationListener接口,这个接口要求bean实现onApplicationEvent()方法来响应事件。
4) 注册监听器,只需要创建监听器的bean,如:
<bean id=”refreshListener” class=”com.spring.foo.ResfreshListener” />
当容器在程序上下文里加载这个bean时会注意到它实现了ApplicationListener,并会在时间被发布时调用它的onApplicationEvent()方法。

注:程序事件是同步处理的,因此对事件的处理要迅速,否则会降低程序的性能。
Bean必须要了解容器(即能获取到容器实例)才能发布事件。

5 让bean了解容器
1)让bean了解bean自己的名称
通过实现BeanNameAware接口,告诉bean它自己的名字。这个接口只有一个setBeanName()方法。只要实现了这个接口,bean被加载时,容器会检测到它实现了BeanNameAware,然后自动调用setBeanName,把<bean>元素里的id或name属性传递过去。

3) 让bean了解所在的容器
跟上面类似,只要bean实现了ApplicationContextAware和BeanFactoryAware接口就可以了。

6.spring里还可以内嵌脚本化的bean,可以是非java实现的bean,没有研究。不梳理了。
  • 大小: 58.6 KB
  • 大小: 50.3 KB
  • 大小: 36.6 KB
  • 大小: 90.7 KB
  • 大小: 88.4 KB
分享到:
评论

相关推荐

    《精通Spring2.X企业应用开发详解》20-23

    概述&lt;br&gt;第1章 Spring概述&lt;br&gt;第2章 快速入门&lt;br&gt;第2篇 Spring核心技术&lt;br&gt;第3章 IoC容器概述&lt;br&gt;第4章 在IoC容器中装配Bean&lt;br&gt;第5章 Spring容器高级主题&lt;br&gt;第6章 Spring AOP基础&lt;br&gt;第7章 基于@AspectJ和Schema的...

    《精通Spring2.X企业应用开发详解》16-19章

    概述&lt;br&gt;第1章 Spring概述&lt;br&gt;第2章 快速入门&lt;br&gt;第2篇 Spring核心技术&lt;br&gt;第3章 IoC容器概述&lt;br&gt;第4章 在IoC容器中装配Bean&lt;br&gt;第5章 Spring容器高级主题&lt;br&gt;第6章 Spring AOP基础&lt;br&gt;第7章 基于@AspectJ和Schema的...

    《精通Spring2.X企业应用开发详解》随书源码1-15章

    概述&lt;br&gt;第1章 Spring概述&lt;br&gt;第2章 快速入门&lt;br&gt;第2篇 Spring核心技术&lt;br&gt;第3章 IoC容器概述&lt;br&gt;第4章 在IoC容器中装配Bean&lt;br&gt;第5章 Spring容器高级主题&lt;br&gt;第6章 Spring AOP基础&lt;br&gt;第7章 基于@AspectJ和Schema的...

    spring bean XML配置入门

    在本文中,我们将深入探讨Spring框架中的Bean XML配置,这是Spring的核心特性之一,它允许我们定义、管理和装配应用中的对象。我们将围绕以下知识点展开: 1. **Spring框架基础**: Spring是一个开源的Java平台,...

    springBoot整合shiro,mybatis

    Map&lt;String, Filter&gt; filters = new HashMap&lt;&gt;(); // 配置自定义过滤器 filters.put("myFilter", new MyCustomFilter()); factoryBean.setFilters(filters); factoryBean.setFilterChainDefinitionMap...

    spring和hibernate整合的优化配置

    &lt;bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"&gt; &lt;property name="mappingResources"&gt; &lt;list&gt; &lt;value&gt;com/demo2do/demo/entity/User.hbm.xml&lt;/value&gt; &lt;value&gt;...

    Spring xml 方式配制的小demo

    Spring提供了一些特定的命名空间,如`context`, `beans`, `aop`等,它们提供了更高级的功能,比如`&lt;context:component-scan&gt;`用于扫描带有特定注解的类,自动创建Bean。 7. ** profiles** Spring允许在不同环境下...

    Spring高级应用,Bean讲解

    XML 配置文件的根元素是 `&lt;beans&gt;,&lt;beans&gt;` 中包含了多个 `&lt;bean&gt;` 子元素,每一个 `&lt;bean&gt;` 子元素定义了一个 Bean,并描述了该 Bean 如何被装配到 Spring 容器中。 关于 `&lt;beans&gt;` 元素的常用属性如下表所示: ...

    springboot 整合mina 源码,nio通讯基础教程,mina框架基础教程.rar

    &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt; &lt;/dependency&gt; &lt;dependency&gt; &lt;groupId&gt;org.apache.mina&lt;/groupId&gt; &lt;artifactId&gt;mina-core&lt;/artifactId&gt; &lt;version&gt;2.1.5&lt;/version&gt; &lt;/dependency&gt; &lt;/...

    Spring高级应用之注入嵌套Bean编程开发技术共1页

    在Spring框架中,高级应用涉及了众多复杂但强大的特性,其中注入嵌套Bean编程开发技术是提高代码组织和模块化的重要手段。嵌套Bean是指在一个Bean定义中引用或包含其他Bean,这种结构允许我们创建更复杂的对象图,...

    spring学习笔记

    - `&lt;refbean&gt;`:同`&lt;ref&gt;`,但在某些上下文中使用。 - `&lt;list&gt;/&lt;set&gt;/&lt;map&gt;/&lt;props&gt;`:用于注入集合类型的数据。 - `&lt;entry&gt;`:用于定义Map中的键值对。 - `&lt;props&gt;`:用于定义Properties类型的属性集。 通过以上...

    Spring的Autowired自动装配(XML版本+Annotation版本+源码+解析)

    通过`&lt;bean&gt;`标签的`autowire`属性,我们可以开启自动装配功能。例如: ```xml &lt;beans&gt; &lt;bean id="myService" class="com.example.MyService"/&gt; &lt;bean id="myClient" class=...

    Struts1SpringHibernate整合总结

    &lt;bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"&gt; &lt;property name="dataSource" ref="dataSource"/&gt; &lt;property name="hibernateProperties"&gt; &lt;props&gt; &lt;prop key...

    Spring2[1].5_IoC(控制反转)容器之容器与Bean(附示例)

    `&lt;import&gt;`元素必须位于所有`&lt;bean&gt;`元素之前。 - 示例: ```xml &lt;beans&gt; &lt;import resource="services.xml"/&gt; &lt;import resource="resources/messageSource.xml"/&gt; &lt;import resource="/resources/themeSource....

    Spring的Bean配置

    1. **属性注入**:通过`&lt;property&gt;`标签设置Bean的属性值,如XML配置示例所示。 2. **构造器注入**:使用`&lt;constructor-arg&gt;`标签指定构造函数参数,或者在注解配置中使用`@Autowired`配合构造函数。 3. **setter...

    spring 装配demo

    &lt;/bean&gt; ``` 4. **基于注解的配置**: 随着Java注解的发展,Spring引入了注解来简化配置。使用`@Component`, `@Service`, `@Repository`和`@Controller`等注解标记类为Spring Bean,而`@Autowired`注解用于自动...

    ioc.zip_ioc_ioc基于_反射

    3. **装配规则**:可以定义多个Bean,并通过`&lt;import&gt;`、`&lt;bean&gt;`等标签来组织和导入其他配置文件,以便进行大规模的系统装配。 在`ioc`目录下的Java文件,通常会包含以下几个关键组件: 1. **Bean工厂**:是创建...

    实验一:Spring IoC中Bean的装置的jar包

    XML配置是最传统的Spring Bean定义方式,它通过`&lt;bean&gt;`标签来声明Bean,设置其属性,以及定义Bean之间的依赖关系。例如: ```xml &lt;beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi=...

    Spring学习资料

    在注入复杂类型的属性时,可以使用`&lt;ref&gt;`标签引用其他Bean,或者使用`&lt;value&gt;`、`&lt;list&gt;`、`&lt;map&gt;`等标签处理基本类型、列表和映射等数据结构。 总之,Spring框架通过IOC和依赖注入提高了代码的灵活性和可维护性,...

Global site tag (gtag.js) - Google Analytics