- 浏览: 495772 次
- 性别:
- 来自: OnePiece
文章分类
- 全部博客 (196)
- --------- 基础----------- (0)
- java 碎碎念 (12)
- java 并行编程 (11)
- java I/O (6)
- java Charset & Encoding (2)
- spring学习笔记 (8)
- 正则表达式 (5)
- web前端-javascript (11)
- web前端-jQuery (7)
- web前端-碎碎念 (1)
- mybatis (0)
- 数据库-通用 (8)
- 数据库-oracle (20)
- nosql-redis (11)
- nosql-mongoDB (1)
- xml (2)
- log4j (2)
- uml (3)
- web services: soap/wsdl (6)
- soa-tuscany (2)
- linux (6)
- ----------修养----------- (0)
- 深入理解java虚拟机 (7)
- java 设计模式 (9)
- 数据结构和算法 (2)
- 读书笔记--代码整洁之道 (2)
- 计算机基础 (1)
- -----------践行---------- (0)
- 重构(refactor) (7)
- jvm-诊断 (4)
- 数据库-让oracle跑得更快 (7)
- Nginx (6)
- ehcache (2)
- 短信开发 (1)
- Servlet+Filter+Listener (2)
- 运维 (6)
- 问题记录 (38)
- 杂七杂八 (12)
最新评论
-
zhanggang807:
第二种方法比较好
<spring> 定时任务每次都执行两次的问题,慎用new ClassPathXmlApplicationContext() -
assasszt:
谢谢分享,很清楚的讲明了原理。
字符集与字符编码简介 -
su0nils000:
难得的笔记
<进阶-2> 打造高效正则表达式 -
足至迹留:
mini188 写道用MD5来解决碰撞是不是也是可行的呢?个人 ...
Hash简介 -
mini188:
用MD5来解决碰撞是不是也是可行的呢?
Hash简介
相对上篇,这次内容有些不太常用,但有些还是非常有用,不能忽略。掌握之后对理解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,没有研究。不梳理了。
一、父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,没有研究。不梳理了。
发表评论
-
<spring-expected at least 1 matching bean> 缺少bean定义
2016-03-04 10:37 14531. 问题描述 ... Error creating bean ... -
<spring-aop> BeanNotOfRequiredTypeException 切面异常
2015-07-24 17:59 67201. 问题描述 往工程里添加切面,定义了<aop:asp ... -
<Spring-Aspect> 切面类(@Aspect)首先必须是bean
2015-07-20 14:08 37281. 问题描述 今天发现老工程里有个日志切面但是总是也没有执行 ... -
<spring> 定时任务每次都执行两次的问题,慎用new ClassPathXmlApplicationContext()
2015-02-26 14:17 58101.问题描述 singleton的bean,spring配置定 ... -
<4> 简记aop原理和使用
2013-08-12 20:27 3016前面把IOC的主要内容都介绍完了,这篇就是另一个spring的 ... -
<2> 基本bean装配
2013-08-10 17:57 1042本篇只介绍基本的最常 ... -
<1> spring学习导读
2013-08-09 22:16 1240最近比较闲,把自己的笔记整理下,虽然都是些入门的东西,还是值得 ...
相关推荐
概述<br>第1章 Spring概述<br>第2章 快速入门<br>第2篇 Spring核心技术<br>第3章 IoC容器概述<br>第4章 在IoC容器中装配Bean<br>第5章 Spring容器高级主题<br>第6章 Spring AOP基础<br>第7章 基于@AspectJ和Schema的...
概述<br>第1章 Spring概述<br>第2章 快速入门<br>第2篇 Spring核心技术<br>第3章 IoC容器概述<br>第4章 在IoC容器中装配Bean<br>第5章 Spring容器高级主题<br>第6章 Spring AOP基础<br>第7章 基于@AspectJ和Schema的...
概述<br>第1章 Spring概述<br>第2章 快速入门<br>第2篇 Spring核心技术<br>第3章 IoC容器概述<br>第4章 在IoC容器中装配Bean<br>第5章 Spring容器高级主题<br>第6章 Spring AOP基础<br>第7章 基于@AspectJ和Schema的...
在本文中,我们将深入探讨Spring框架中的Bean XML配置,这是Spring的核心特性之一,它允许我们定义、管理和装配应用中的对象。我们将围绕以下知识点展开: 1. **Spring框架基础**: Spring是一个开源的Java平台,...
Map<String, Filter> filters = new HashMap<>(); // 配置自定义过滤器 filters.put("myFilter", new MyCustomFilter()); factoryBean.setFilters(filters); factoryBean.setFilterChainDefinitionMap...
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="mappingResources"> <list> <value>com/demo2do/demo/entity/User.hbm.xml</value> <value>...
Spring提供了一些特定的命名空间,如`context`, `beans`, `aop`等,它们提供了更高级的功能,比如`<context:component-scan>`用于扫描带有特定注解的类,自动创建Bean。 7. ** profiles** Spring允许在不同环境下...
XML 配置文件的根元素是 `<beans>,<beans>` 中包含了多个 `<bean>` 子元素,每一个 `<bean>` 子元素定义了一个 Bean,并描述了该 Bean 如何被装配到 Spring 容器中。 关于 `<beans>` 元素的常用属性如下表所示: ...
<artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.apache.mina</groupId> <artifactId>mina-core</artifactId> <version>2.1.5</version> </dependency> </...
在Spring框架中,高级应用涉及了众多复杂但强大的特性,其中注入嵌套Bean编程开发技术是提高代码组织和模块化的重要手段。嵌套Bean是指在一个Bean定义中引用或包含其他Bean,这种结构允许我们创建更复杂的对象图,...
- `<refbean>`:同`<ref>`,但在某些上下文中使用。 - `<list>/<set>/<map>/<props>`:用于注入集合类型的数据。 - `<entry>`:用于定义Map中的键值对。 - `<props>`:用于定义Properties类型的属性集。 通过以上...
通过`<bean>`标签的`autowire`属性,我们可以开启自动装配功能。例如: ```xml <beans> <bean id="myService" class="com.example.MyService"/> <bean id="myClient" class=...
<bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="hibernateProperties"> <props> <prop key...
`<import>`元素必须位于所有`<bean>`元素之前。 - 示例: ```xml <beans> <import resource="services.xml"/> <import resource="resources/messageSource.xml"/> <import resource="/resources/themeSource....
1. **属性注入**:通过`<property>`标签设置Bean的属性值,如XML配置示例所示。 2. **构造器注入**:使用`<constructor-arg>`标签指定构造函数参数,或者在注解配置中使用`@Autowired`配合构造函数。 3. **setter...
</bean> ``` 4. **基于注解的配置**: 随着Java注解的发展,Spring引入了注解来简化配置。使用`@Component`, `@Service`, `@Repository`和`@Controller`等注解标记类为Spring Bean,而`@Autowired`注解用于自动...
3. **装配规则**:可以定义多个Bean,并通过`<import>`、`<bean>`等标签来组织和导入其他配置文件,以便进行大规模的系统装配。 在`ioc`目录下的Java文件,通常会包含以下几个关键组件: 1. **Bean工厂**:是创建...
XML配置是最传统的Spring Bean定义方式,它通过`<bean>`标签来声明Bean,设置其属性,以及定义Bean之间的依赖关系。例如: ```xml <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi=...
在注入复杂类型的属性时,可以使用`<ref>`标签引用其他Bean,或者使用`<value>`、`<list>`、`<map>`等标签处理基本类型、列表和映射等数据结构。 总之,Spring框架通过IOC和依赖注入提高了代码的灵活性和可维护性,...