spring4.x

spring IOC容器高级主题

2016-05-14  本文已影响377人  不迷失

容器扩展
通常开发者无需自己实现APplicationContext,而是使用插件扩展Spring IoC容器,插件是某些指定的集成接口的实现。
使用BeanPostProcessor自定义bean
BeanPostProcessor
接口定义了实例化逻辑、依赖逻辑等回调方法,即可以自定义也可以覆盖容器默认方法。若果要在Spring容器完成实例化、配置、初始化bean之后执行自定义逻辑,则以插件方式实现BeanPostProcessor。
可以配置多个BeanPostProcessor实例,可以设置BeanPostProcessors的order属性来控制其执行次序。让BeanPostProcessor实现Ordered接口,就能设置其属性。
org.springframework.beans.factory.config.BeanPostProcessor接口有2个回调方法组成。当这样的类在容器内后,容器创建所有bean,在容器初始化方法(比如InitializingBean的afterProperieSet()方法和其他所有的声明的init方法)和所有bean 初始化回调之前,运行post-processor回调,这意味着我们可以通过它自定义bean的任何数据。

ApplicationContext自动探测在配置元数据中定义的BeanPostProcessor。ApplicationContext注册这些bean为post-processors,这样就可以在bean创建之前调用。Bean的post-processors可以像其他bean那样部署到容器里。

注意,在configuration类中,使用@Bean工厂方法声明BeanPostProcessor,该工厂方法的返回类型必须是该实现类或者至少得是org.springframework.beans.factory.config.BeanPostProcessor接口,清楚的标识出post-processor。否则,ApplicationContext不会开启根据类型自动探测。因为BeanPostProcessor需要尽早的实例化,这样在容器中即可用于其他bean的初始化,因此这种尽早的类型探测至关重要。
下面 示例中讲解了在ApplicationContext中如何撰写、注册、使用BeanPostProcessors。示例展示了一个自定义BeanPostProcessor实现,功能是在容器创建bean时,调用每一个bean的toString()方法并输出到控制台。

package spring4;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * Created by ${javajidi_com}.
 */
@Component
public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {

    // simply return the instantiated bean as-is
    public Object postProcessBeforeInitialization(Object bean,
                                                  String beanName) throws BeansException {
        System.out.println("Bean '" + beanName + "' before created : " + bean.toString());
        return bean; // we could potentially return any object reference here...
    }

    public Object postProcessAfterInitialization(Object bean,
                                                 String beanName) throws BeansException {
        System.out.println("Bean '" + beanName + "' created : " + bean.toString());
        return bean;
    }
}


package spring4;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * Created by admin on 2016/5/14.
 */
@Configuration("name")//表示这是一个配置信息类,可以给这个配置类也起一个名称
@ComponentScan("spring4")//类似于xml中的<context:component-scan base-package="spring4"/>
public class Config {


}


package spring4;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * Created by java技术 on 2016/5/13.
 */

public class Application {


    public static void main(String[] arg){
        //初始化spring容器,由于使用的是注解,没有xml文件,所有不再使用ClasspathXmlApplicationContext
        ApplicationContext context=new AnnotationConfigApplicationContext(Config.class);
    }
}

控制台输出
Bean 'org.springframework.context.event.internalEventListenerProcessor' before created : org.springframework.context.event.EventListenerMethodProcessor@48b6434f
Bean 'org.springframework.context.event.internalEventListenerProcessor' created : org.springframework.context.event.EventListenerMethodProcessor@48b6434f
Bean 'org.springframework.context.event.internalEventListenerFactory' before created : org.springframework.context.event.DefaultEventListenerFactory@21155013
Bean 'org.springframework.context.event.internalEventListenerFactory' created : org.springframework.context.event.DefaultEventListenerFactory@21155013
Bean 'name' before created : spring4.Config$$EnhancerBySpringCGLIB$$1da6aa52@7a872be7
Bean 'name' created : spring4.Config$$EnhancerBySpringCGLIB$$1da6aa52@7a872be7
Bean 'compent' before created : spring4.Compent@cc99e73
Bean 'compent' created : spring4.Compent@cc99e73

接下来的扩展点讲一讲
org.springframework.beans.factory.config.BeanFactoryPostProcessor
此接口的语法和BeanPostProcessor类似,有一个主要的不同之处:BeanFactoryPostProcessor操作bean的配置元数据;也就是,Spring IoC容器允许BeanFactoryPostProcessor读取配置元数据并且在容器实例化bean之前可能修改配置。

可以配置多个BeanFactoryPostProcessors,通过设置order属性控制它们的执行次序。BeanFactoryPostProcessor若是实现了Ordered接口,则可设置该属性。若是自定义BeanFactorPostProcessor,同时得考虑实现Ordered接口。
为了让配置元数据的改变应用,声明在ApplicationContext内的bean工厂post-processor都是自动执行。Spring包含一系列的预先定义的bean工厂post-processors,比如PropertyOverrideConfigurer和PropertyPlaceholderConfigurer。也可以使用自定义BeanFactoryPostProcessor,比如注册一个自定义属性编辑器。
ApplicationContext自动探测BeanFactoryPostProcessor接口的实现类。容器使用这些bean作为bean工厂post-processors。可以像其他bean那样将post-processor部署在容器内。

BeanFactoryPostProcessors的最经典应用就是属性支持占位符了。
可以使用PropertyPlaceholderConfigurer将bean的属性值使用标准的Java Properties格式定义在一个单独的文件中。这样可以将应用的自定义环境配置属性隔离出来,比如数据库URLs和密码,这样就降低了修改容器内XML配置或者Java 代码的的复杂性和风险。
考虑下面的XML配置片段,使用了placeholder值定义了DataSource。样例展示了一个外部的Properties
文件的属性配置。运行时,PropertyPlaceholderConfigurer会应用到配置元数据中,替换指定格式的placeholders,格式为${property-name}。

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations" value="classpath:com/foo/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>

在标准java Properties格式文件中实际的值:

jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root

因此,字串${jdbc.username}在运行时赋值为sa其他的${key}都会被替换为文件中与key对应的值。PropertyPlaceholderConfigurer检查bean定义中大多数的placeholders占位符,placeholder的前缀和后缀都是自定义的。
PropertyPlaceholderConfigurer不仅仅检索指定的Properties文件。默认情况,若是在指定的Properties
配置文件中找不到指定的属性property,也会检查Java 的系统属性System properties。通过设置systemPropertiesMode属性的值,定义默认查找行为,该属性值有几个取值:
never:不检查系统属性
fallback:如果未在指定文件中解析出属性值,则检查系统属性。此项为默认行为。
override:先检查系统属性。系统属性会覆盖其他配置文件中的属性。

微信公众号: java技术
技术交流群: 245130488

上一篇下一篇

猜你喜欢

热点阅读