在运行时访问Spring bean定义属性以进行日志记录

时间:2015-04-12 00:33:20

标签: spring

我希望能够在运行时从我的Spring配置文件中配置的某些bean定义(即我的web.xml中由 contextConfigLocation 设置的bean定义)中读取属性。我想这样做,以便我可以记录属性值,这样当我收到诊断日志文件时,我可以看到系统集成商如何设置应用程序。

查看Spring调试日志,我可以看到它们是由类XmlBeanDefinitionReader从配置文件中读取的。我猜测Spring提供了一种方法来访问生成的bean定义,但我找不到它。

作为示例,这些是我想要读取配置的bean定义。

<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
    destroy-method="close">
    <property name="driverClass">
        <value>com.mysql.jdbc.Driver</value>
    </property>
    <property name="jdbcUrl">
        <value>jdbc:mysql://localhost:3306/an_example_db</value>
    </property>
    <property name="user">
        <value>exampleuser</value>
    </property>
    <property name="password">
        <value>examplepwd</value>
    </property>
</bean>
<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource">
        <ref bean="dataSource" />
    </property>
    <property name="packagesToScan" value="com.my.example.entity" />
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.id.new_generator_mappings">true</prop>
            <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
            <prop key="hibernate.hbm2ddl.auto">validate</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.format_sql">true</prop>
            <prop key="hibernate.query.substitutions">true 1, false 0, yes 'Y', no 'N'</prop>
        </props>
    </property>
</bean>

请注意,这些只是示例。如果可能的话,我希望能够读取任何bean定义的属性。

1 个答案:

答案 0 :(得分:2)

您可以创建一个插入所有 bean的构建后阶段的bean,此时您可以执行日志记录。这可以通过实现BeanPostProcessor的bean来完成。

示例:

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

@Component
public class BeanPostProcessorAuditChecker implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean: " + beanName + " initialized with props: " + bean);
        return bean;
    }
}

注意事项:

  1. 可以像往常一样使用注释(如上所述)或XML配置来定义此bean。
  2. 界面正在拦截所有 bean结构。
  3. 接口方法实现期望您返回bean对象。
  4. 在我的例子中,我只是System.out.println,但你真的想要SLF4J或其他日志。另外,我相信toString()方法已正确实现,可以公开您感兴趣的属性。
  5. 如果您希望过滤日志记录仅发生在bean的子集上而不是所有bean上,那么您必须自己在方法体中使用反射
  6. 段:

     if(bean instanceof DataSource || 
        bean instanceof SessionFactory) { log.debug("{}",bean); }
    

    由于您的业务领域未知,因此提供了一些替代方案:

    1. 如果您可以切入域名,那么您想要插入 AOP 是另一种替代代理方法。
    2. 您可以在bean上公开 JMX 并在外部使用(解耦方法)
    3. 另一种解耦方法是使用ApplicationEventPublisher发布事件。这是因为在您的情况下不可取 - 您只对建筑物属性感兴趣。

    4. 编辑前

      您演示的bean是1)单例(凭借Spring默认范围)和2)bean设置后(通过set方法调用)不太可能更改属性。

      在这些假设下,为什么你不在道具文件中积累这些属性值

      database.driverClass=com.mysql.jdbc.Driver
      database.user=exampleuser
      ...
      

      将它们注入上下文定义

      ...
      <property name="user" value="#{database.user}"/>
      ...
      

      并使用PropertyPlaceholderConfigurer检查值。