zoukankan      html  css  js  c++  java
  • Spring Container的扩展点

    转自: http://blog.csdn.net/kkdelta/article/details/5488430

    Spring在解析完配置文件后,会调用一些callback方法,使用Spring的开发者可以通过提供这些callback方法达到对Spring Container的扩展.
    1.   通过实现BeanPostProcessor来完成对某些Bean的一些定制, BeanPostProcessor定义了两个方法, postProcessBeforeInitialization(Object bean, String beanName)和postProcessAfterInitialization(Object bean, String beanName)。 postProcessBeforeInitialization会在Spring对bean初始化完成之后 , 依赖注册(对property指定的成员变量完成了赋值)已经完成 , 但是Container还没有调用申明的initialization方法(如afterPropertiesSet, init-method)之前被调用.postProcessAfterInitialization会在在Container调用申明的initialization方法(如afterPropertiesSet)之后被调用.如果需要有多个实现了BeanPostProcessor的类,可以通过让其实现Ordered接口来控制这些类的callback被调用的顺序。这种bean的post-processor一般用来检查bean是否实现了某个接口 , 或者把bean包装成某个proxy,Spring的AOP某些框架类就是实现了BeanPostProcessor.

    例:

    public class MyBeanPostProcessor implements BeanPostProcessor,
            InvocationHandler {
        private Object proxyobj;
        public MyBeanPostProcessor() {   
        }
        public MyBeanPostProcessor(Object obj) {
            proxyobj = obj;
        }
        public Object postProcessBeforeInitialization(Object bean, String beanName)
                throws BeansException {
            System.out.println("postProcessBeforeInitialization Bean '" + beanName
                    + "' created : " + bean.toString());
            if (bean instanceof Intf) {
                Class cls = bean.getClass();
                return Proxy.newProxyInstance(cls.getClassLoader(), cls
                        .getInterfaces(), new MyBeanPostProcessor(bean));
            } else {
                return bean;
            }
        }
        public Object postProcessAfterInitialization(Object bean, String beanName)
                throws BeansException {
            System.out.println("postProcessAfterInitialization Bean '" + beanName
                    + "' created : " + bean.toString());
            return bean;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            System.out.println("proxy is " + proxy.getClass().getName());
            System.out.println("before calling " + method);
    
            if (args != null) {
                for (int i = 0; i < args.length; i++) {
                    System.out.println(args[i] + "");
                }
            }
            Object o = method.invoke(proxyobj, args);
            System.out.println("after calling " + method);
            return o;
        }
    }
    public interface Intf {
        public String testFunc();
    }
    public class IntfBean implements Intf {
        private String strVal = "default value";
        @Override
        public String testFunc() {
            // TODO Auto-generated method stub
            return strVal;
        }
    }
    
    <bean id="IntfBean" class="com.test.spring.extent.IntfBean" />
    <bean class="com.test.spring.extent.MyBeanPostProcessor" />

    注意这里实现BeanPostProcessor的类是针对Ioc容器里其他的bean调用这两个方法,不是针对BeanPostProcessor自身和其他BeanPostProcessor调用这两个方法, 如果在配置文件里就只有BeanPostProcessor本身, 没有其他的bean, 如只有<beanclass="com.test.spring.extent.MyBeanPostProcessor"/>配置,postProcessBeforeInitialization和postProcessAfterInitialization这两个方法是不会被调用的.BeanPostProcessor会在普通bean被初始化之前先被容器初始化.
    调用代码:
    Intf intfBean = (Intf) ctx.getBean("IntfBean");
    System.out.println(intfBean.testFunc());
    这样,MyBeanPostProcessor会把实现Intf接口的bean包装成一个proxy.

    2. 通过实现BeanFactoryPostProcessor接口来操作配置文件,对配置的元数据进行特制。 Spring IoC容器允许BeanFactoryPostProcessor在容器实际实例化任何其它的bean之前读取配置元数据,并有可能修改它。Spring自身的PropertyPlaceholderConfigurer 就实现了这个接口 , 通过对XML配置文件中使用占位符 , PropertyPlaceholderConfigurer从别的property文件中读取值进行替换。
    例子:从ext.properties读取值替换${TEST.PROP1},${TEST.PROP2}.

    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
            <property name="locations" value="classpath:conf/ext.properties" />
            <property name="properties">
                <value>TEST.PROP3=inside property</value>
            </property>
        </bean>
        <bean id="PropReplaceBean" class="com.test.spring.extent.PropReplaceBean">
            <property name="strVal" value="${TEST.PROP1}" />
            <property name="intVal" value="${TEST.PROP2}" />
            <property name="insideProp" value="${TEST.PROP3}" />
        </bean>

    通常比较有用的场景是数据库的url,用户名,密码的配置,还可以用来动态指定某个bean的类名,把XMl文件和property文件分开维护更容易。
    <bean id="xxxBean" class="${com.xxx.class}"/>
    自定义的BeanFactoryPostProcessor,通过实现Ordered接口可以改变被callback的顺序。 callback方法中的ConfigurableListableBeanFactory beanFactory提供了配置文件的元数据。(*碰到一个困惑的问题是: PropertyPlaceholderConfigurer的order是 Integer.MAX_VALUE,却发现它比自己定义的order 为-1的 processor先执行.)

    <bean class="com.test.spring.extent.MyBeanFactoryPostProcessor" />
    public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor,
            Ordered {
        private int order = -1;
        public void setOrder(int order) {
            this.order = order;
        }
        public int getOrder() {
            return this.order;
        }
        @Override
        public void postProcessBeanFactory(
                ConfigurableListableBeanFactory beanFactory) throws BeansException {
            BeanDefinition beanDefinition = beanFactory
                    .getBeanDefinition("PropReplaceBean");
            MutablePropertyValues pvs = beanDefinition.getPropertyValues();
            PropertyValue[] pvArray = pvs.getPropertyValues();
            for (PropertyValue pv : pvArray) {
                System.out.println(pv.getName() + "  " + pv.getValue().getClass());
            }
        }
    }

    Spring检测到BeanPostProcessor和BeanFactoryPostProcessor后会由容器自动调用它们的callback方法,不用在代码里主动的去调用.

  • 相关阅读:
    Nmap绕过防火墙&脚本的使用
    Nmap在实战中的高级用法
    kali&BT安装好之后无法上网或者无法获得内网IP
    [转]谈渗透测试方法和流程
    xssless
    国内外有名的安全扫描工具,你知道几个?
    Linux下如果忘记了Mysql的root密码该怎么办?
    JSP手动注入 全
    sqlmap用户手册 [详细]
    Windows系统如何使用sqlmap
  • 原文地址:https://www.cnblogs.com/vincent2010/p/4773002.html
Copyright © 2011-2022 走看看