Bean定义的继承、容器扩展点
-
定义继承
在
<bean>
元素中定义parent
属性,使这个bean定义继承另一个bean定义。<bean id="inheritedTestBean" abstract="true" class="org.springframework.beans.TestBean"> <property name="name" value="parent"/> <property name="age" value="1"/> </bean> <bean id="inheritsWithDifferentClass" class="org.springframework.beans.DerivedTestBean" parent="inheritedTestBean" init-method="initialize"> <property name="name" value="override"/> <!-- the age property value of 1 will be inherited from parent --> </bean>
子定义可以继承父定义的作用域,构造器参数,属性值;也可以覆盖父定义的方法,比如初始话回调,销毁回调和静态工厂方法等。
下面的设置总是取自子定义:依赖、自动装配模式、依赖检查和懒启动。
如果在一个bean定义中
abstract
属性为true
,那么这个bean将不会被实例化,它只会作为子定义的模板。如果一个bean定义没有指定class
属性,一定要配置abstract
属性。 -
使用
BeanPostProcessor
定制Bean2.1
BeanPostProcessor
实现
BeanPostProcessor
接口定义的方法,我们可以定义自己的实例化逻辑和依赖解析逻辑等。也可以在容器完成实例化、配置、和初始化bean之后完成我们定义的一些逻辑。如果我们实现了多个
BeanPostProcessor
,我们还可以通过实现Ordered
接口来定义这些工作逻辑的执行顺序。每个
post-processor
只在自己所在的容器中起作用。容器将自动搜寻并注册那些实现了
BeanPostProcessor
接口且在配置元数据中有定义的bean。下面是一个简单的例子,这个post-processor
将在每个bean初始化后都打印结果。class InitialResultPostProcessor implements BeanPostProcessor, Ordered { public static Logger log = Logger.getLogger("com.heisenberg.spring"); //post-processor的执行顺序 @Override public int getOrder() { return 0; } //每一个bean初始化之前回调该方法 @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } //每一个bean初始化之后回调该方法 @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { log.info(Utils.buildLogInfo(beanName + " has been initialed")); return bean; } }
<bean id="postProcessor" class="com.heisenberg.spring.pojo.InitialResultPostProcessor"/>
-
使用
BeanFactoryPostProcessor
定制配置数据元从语义上看,
BeanFactoryPostProcessor
与BeanPostProcessor
相似,但是它们有一个主要的不同点:BeanFactoryPostProcessor
操作bean的配置数据元。Spring IoC容器让一个BeanFactoryPostProcessor
读取配置信息,也允许它在初始化这些bean(除BeanFactoryPostProcessor
bean之外)之前修改他们的配置。如果我们实现了多个
BeanFactoryPostProcessor
,我们还可以通过实现Ordered
接口来定义这些工作逻辑的执行顺序。每个
bean factory post-processor
只在自己所在的容器中起作用。Spring包含几个预定义的
bean factory post processor
,如PropertyOverrideConfigurer
和PropertySourcesPlaceholderConfigurer
。BeanPostProcessor
和BeanFactoryPostProcessor
会预初始化,即使我们将这些bean设置为lazy-init=true
,或者整个容器的bean都懒加载default-lazy-init=true
。public interface BeanFactoryPostProcessor { void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException; }
3.1
PropertySourcesPlaceholderConfigurer
org.springframework.context.support.PropertySourcesPlaceholderConfigurer
实现了BeanFactoryPostProcessor
接口。这个类可以让我们在单独的文件中配置bean的属性值。<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"> <property name="locations" value="classpath:com/something/jdbc.properties"/> </bean> <bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean>
jdbc.properties
文件内容:jdbc.driverClassName=org.hsqldb.jdbcDriver jdbc.url=jdbc:hsqldb:hsql://production:9002 jdbc.username=sa jdbc.password=root
通过上面的配置,
dataSource
bean的属性值在应用运行时被替换。我们也可以使用专门的元素
<context>
来配置property placeholder
:<!-- location的值可以是多个用,隔开的文件路径 --> <context:property-placeholder location="classpath:com/something/jdbc.properties"/>
property placeholder
不仅可以用来替换bean的基础类型值,还可以用来替换<bean>
元素的class
属性值。当我们在运行时必须要指定一个实现类型时,这个特性就十分的有用<bean class="org.springframework.beans.factory.config.PropertySourcesPlaceholderConfigurer"> <property name="locations"> <value>classpath:com/something/strategy.properties</value> </property> <property name="properties"> <value>custom.strategy.class=com.something.DefaultStrategy</value> </property> </bean> <bean id="serviceStrategy" class="${custom.strategy.class}"/>
3.2
PropertyOverrideConfigurer
与
PropertySourcesPlaceholderConfigurer
类似,但是PropertyOverrideConfigurer
允许bean的属性有默认值或者没有值。如果一个Properties
文件没有对应于这个bean某个属性的实体时,这个属性就使用某人值,否则默认值将被覆盖。Properties
文件的格式为:dataSource.driverClassName=com.mysql.jdbc.Driver dataSource.url=jdbc:mysql:mydb
上面的配置是
dataSource
bean的driverClassName
与url
属性的覆盖值。还支持符合属性名:aaa.bbb.ccc=ddd
bean
aaa
的域bbb
的ccc
属性的覆盖值为:ddd简便的
PropertyOverrideConfigurer
bean配置:<context:property-override location="classpath:override.properties"/>
-
通过
FactoryBean
制定实例化逻辑(注意不是BeanFactory
)FactoryBean
接口有3个方法:public interface FactoryBean<T> { String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType"; @Nullable T getObject() throws Exception; @Nullable Class<?> getObjectType(); default boolean isSingleton() { return true; } }
在容器中注册一个
FactoryBean
,并为其设置一个id(这里假设为:factoryBean),那么调用ApplicationContext
的getBean()
方法,入参beanName
的值若是"factoryBean",那么我们实现的getObject
方法将会被调用。若入参beanName
的值为:"&factoryBean"(多了&
前缀),我们将的到factoryBean
bean本身的实例。若一个bean的实例化过程十分的复杂,使用
FactoryBean
是一个非常好的选择。