spring in action 2.0读书笔记(3)
spring in action 2.0读书笔记(三)
Spring inheritance(different from Java inheritance): abstract and parent, is commonly used to reduce the amount of redundant XML. e.g: TransactionProxyFactoryBean.
Spring提供了method injection功能,使你能够在runtime期间把method注入到class里.Spring提供了2种方式的method injection:
1.Method replacement—Enables existing methods (abstract or concrete) to be replaced at runtime with new implementations.
2.Getter injection—Enables existing methods (abstract or concrete) to be replaced at runtime with a new implementation that returns a specific bean from the Spring context. (这种方式是for"使用get开头的,而且返回值是在spring里有bean定义类型"的方法)
There’s no need to write a MethodReplacer class.
Injecting non-Spring beans
对于在spring里有定义bean,但又不是通过spring来创建的class,又应该如何使用spring呢?这种情况是可能的:例如,一个由ORM创建的object则不是spring创建的。
第一步:把bean定义成abstract:
第二步:如果把上面的定义(注意上面设置的id)和class联系起来
@Configurable的作用有2个:
1> 它表明Instrumentalist的实例会被纳入和配置到spring container里,即使它是在outside of spring创建。
2> 它把Instrumentalist class与id为pianist联系在一起,当spring在配置一个实例时,它会寻找pianist bean作为模板来进行配置(包括DI)
第三步:在spring configure file里添加下列代码
它表示有一些在外部创建的beans,需要被配置和纳入进spring container.
请注意:<aop:spring-configured/>是用到aspectJ,这意味着你的APP必须在一个AspectJ-enabled JVM里运行。
The best way to AspectJ-enable a Java 5 JVM is to start it with the following JVM argument:
-javaagent:/path/to/aspectjweaver.jar
Registering custom property editors
extends java.beans.PropertyEditorSupport
CustomEditorConfigurer实质上是一个BeanFactoryPostProcessor,因此它会在bean factory初始化之后调用registerCustomEditor()方法来把custom editors load进BeanFactory里。
Postprocessing beans
PostProcessor有2种:
1) Bean PostProcessor (注意:BeanPostProcessor是for all beans的,not for one bean)implements BeanPostProcessor
postProcessBeforeInitialization()方法是在bean初始化之前被调用(即在bean定义中设置的“init-method”方法执行之前或实现InitializingBean接口的Bean的afterPropertiesSet()方法执行之前)
postProcessAfterInitialization()方法是在初始化之后被调用(即在bean定义中设置的“init-method”方法执行之后或实现InitializingBean接口的Bean的afterPropertiesSet()方法执行之后)
2) Bean Factory PostProcessor implements BeanFactoryPostProcessor
postProcessBeanFactory()方法会在all beans loaded之后,任何bean(包括BeanPostProcessor beans)被初始化(instantiated)之前,被spring container所调用。
Externalizing configuration properties
Resolving resource messages
Spring提供了一些Aware接口,如BeanFactoryAware、ApplicationContextAware、ResourceLoaderAware、ServletContextAware等等。比如,实现了BeanFactoryAware接口的bean,Spring容器会自动把BeanFactory对象注入该bean(当然,前提是该bean有一个BeanFactory变量),而实现了ApplicationContextAware接口的bean,会自动把ApplicationContext对象注入该bean(当然,前提是该bean有一个ApplicationContext变量)
Decoupling with application events
第一步:定义一个application event,它扩展了ApplicationEvent抽象类
第二步:定义一个Application listener,它实现org.springframework.context.ApplicationListener接口。
第三步:在spring里注册该listener。
第四步: 用来publish event的bean,因为publish event需要用到applicationcontext,所以implements ApplicationContextAware
Scripting beans
把script bean注入到java class bean
把java class bean注入到script bean
Refreshing scripted beans
Writing scripted beans inline
<bean id="baseSaxophonist" class="com.springinaction.springidol.Instrumentalist" abstract="true"> <property name="instrument" ref="saxophone" /> <property name="song" value="Jingle Bells" /> </bean> <bean id="kenny" parent="baseSaxophonist" /> <bean id="david" parent="baseSaxophonist" />
Spring inheritance(different from Java inheritance): abstract and parent, is commonly used to reduce the amount of redundant XML. e.g: TransactionProxyFactoryBean.
Spring提供了method injection功能,使你能够在runtime期间把method注入到class里.Spring提供了2种方式的method injection:
1.Method replacement—Enables existing methods (abstract or concrete) to be replaced at runtime with new implementations.
<bean id="magicBox" class="com.springinaction.springidol.MagicBoxImpl"> <replaced-method name="getContents" replacer="tigerReplacer" /> </bean> <bean id="tigerReplacer" class="com.springinaction.springidol.TigerReplacer" /> import org.springframework.beans.factory.support.MethodReplacer; public class TigerReplacer implements MethodReplacer { public Object reimplement(Object target, Method method, Object[] args) throws Throwable { return "A ferocious tiger"; } }
2.Getter injection—Enables existing methods (abstract or concrete) to be replaced at runtime with a new implementation that returns a specific bean from the Spring context. (这种方式是for"使用get开头的,而且返回值是在spring里有bean定义类型"的方法)
<bean id="stevie" class="com.springinaction.springidol.Instrumentalist"> <lookup-method name="getInstrument" bean="guitar" /> </bean>
There’s no need to write a MethodReplacer class.
Injecting non-Spring beans
对于在spring里有定义bean,但又不是通过spring来创建的class,又应该如何使用spring呢?这种情况是可能的:例如,一个由ORM创建的object则不是spring创建的。
第一步:把bean定义成abstract:
<bean id="pianist" class="com.springinaction.springidol.Instrumentalist" abstract="true"> <property name="instrument"> <bean class="com.springinaction.springidol.Piano" /> </property> </bean>
第二步:如果把上面的定义(注意上面设置的id)和class联系起来
@Configurable("pianist") public class Instrumentalist implements Performer { … }
@Configurable的作用有2个:
1> 它表明Instrumentalist的实例会被纳入和配置到spring container里,即使它是在outside of spring创建。
2> 它把Instrumentalist class与id为pianist联系在一起,当spring在配置一个实例时,它会寻找pianist bean作为模板来进行配置(包括DI)
第三步:在spring configure file里添加下列代码
<aop:spring-configured />
它表示有一些在外部创建的beans,需要被配置和纳入进spring container.
请注意:<aop:spring-configured/>是用到aspectJ,这意味着你的APP必须在一个AspectJ-enabled JVM里运行。
The best way to AspectJ-enable a Java 5 JVM is to start it with the following JVM argument:
-javaagent:/path/to/aspectjweaver.jar
Registering custom property editors
extends java.beans.PropertyEditorSupport
public class PhoneEditor extends java.beans.PropertyEditorSupport { //text value example “111-111-111” public void setAsText(String textValue) { String areaCode = textValue.substring(0,3); String prefix = textValue.substring(4,7); String number = textValue.substring(8); PhoneNumber phone = new PhoneNumber(areaCode, prefix, number); setValue(phone); } } <bean class="org.springframework.beans.factory.config.CustomEditorConfigurer"> <property name="customEditors"> <map> <entry key="com.springinaction.chapter03.propeditor.PhoneNumber"> <bean id="phoneEditor" class="com.springinaction.chapter03.propeditor.PhoneEditor"> </bean> </entry> </map> </property> </bean>
CustomEditorConfigurer实质上是一个BeanFactoryPostProcessor,因此它会在bean factory初始化之后调用registerCustomEditor()方法来把custom editors load进BeanFactory里。
Postprocessing beans
PostProcessor有2种:
1) Bean PostProcessor (注意:BeanPostProcessor是for all beans的,not for one bean)implements BeanPostProcessor
postProcessBeforeInitialization()方法是在bean初始化之前被调用(即在bean定义中设置的“init-method”方法执行之前或实现InitializingBean接口的Bean的afterPropertiesSet()方法执行之前)
postProcessAfterInitialization()方法是在初始化之后被调用(即在bean定义中设置的“init-method”方法执行之后或实现InitializingBean接口的Bean的afterPropertiesSet()方法执行之后)
2) Bean Factory PostProcessor implements BeanFactoryPostProcessor
postProcessBeanFactory()方法会在all beans loaded之后,任何bean(包括BeanPostProcessor beans)被初始化(instantiated)之前,被spring container所调用。
Externalizing configuration properties
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="jdbc.properties" /> </bean> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="url" value="${database.url}" /> <property name="driverClassName" value="${database.driver}" /> <property name="username" value="${database.user}" /> <property name="password" value="${database.password}" /> </bean>
Resolving resource messages
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename"> <value>trainingtext</value> </property> </bean> <spring:message code="computer"/>
Spring提供了一些Aware接口,如BeanFactoryAware、ApplicationContextAware、ResourceLoaderAware、ServletContextAware等等。比如,实现了BeanFactoryAware接口的bean,Spring容器会自动把BeanFactory对象注入该bean(当然,前提是该bean有一个BeanFactory变量),而实现了ApplicationContextAware接口的bean,会自动把ApplicationContext对象注入该bean(当然,前提是该bean有一个ApplicationContext变量)
Decoupling with application events
第一步:定义一个application event,它扩展了ApplicationEvent抽象类
第二步:定义一个Application listener,它实现org.springframework.context.ApplicationListener接口。
class HeartbeatForwarder implements ApplicationListener { public void onApplicationEvent(ApplicationEvent event) { if (event instanceof HeartbeatEvent) { System.out.println("Received heartbeat event: " + event.getTimestamp()); } } }
第三步:在spring里注册该listener。
第四步: 用来publish event的bean,因为publish event需要用到applicationcontext,所以implements ApplicationContextAware
class HeartbeatTask extends TimerTask implements ApplicationEventPublisherAware { private ApplicationEventPublisher eventPublisher; public void run() { HeartbeatEvent event = new HeartbeatEvent(this); eventPublisher.publishEvent(event); } public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) { this.eventPublisher = eventPublisher; } }
Scripting beans
把script bean注入到java class bean
<lang:jruby id="lime" script-source="classpath:com/springinaction/scripting/Lime.rb" script-interfaces="com.springinaction.scripting.Lime" />
把java class bean注入到script bean
<lang:groovy id="coconut" script-source="classpath:com/springinaction/scripting/Coconut.groovy"> <lang:property name="lime" ref="lime" /> </lang:groovy>
Refreshing scripted beans
<lang:jruby id="lime" script-source="classpath:com/springinaction/scripting/Lime.rb" script-interfaces="com.springinaction.scripting.Lime" refresh-check-delay="5000"/>
Writing scripted beans inline
<lang:bsh id="lime" script-interfaces="com.springinaction.scripting.Lime"> <lang:inline-script><![CDATA[ void drink() { System.out.println("Called the doctor woke him up!"); } ]]> </lang:inline-script> </lang:bsh>