如何基于Web服务器覆盖Spring bean

时间:2010-03-15 08:45:24

标签: spring deployment tomcat websphere

我正在构建一个应该在Tomcat和WebSphere上运行的webapp,并且我已经设法将几乎所有差异都用于默认值,我可以覆盖它们以便在Tomcat服务器上进行部署。

我需要对身份验证提供程序bean进行另一次覆盖...

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    if(isWebSphere()){
        LOG.warn("Running on WebSphere... not overriding default authentication mechanism.");
        return;
    }
    LOG.info("Running on Tomcat... overriding authentication provider bean ("+AUTHENTICATION_PROVIDER_BEAN+")");
    if (beanFactory.containsBean(AUTHENTICATOR_BEAN) && beanFactory.containsBean(POPULATOR_BEAN) && beanFactory.containsBean(USERDETAIL_PROVIDER_BEAN)){
        LdapAuthenticator authenticator = (LdapAuthenticator) beanFactory.getBean(AUTHENTICATOR_BEAN);
        LdapAuthoritiesPopulator populator = (LdapAuthoritiesPopulator) beanFactory.getBean(POPULATOR_BEAN);
        UserDetailProvider userDetailProvider = (UserDetailProvider) beanFactory.getBean(USERDETAIL_PROVIDER_BEAN);
        ExtendedLdapAuthenticationProvider override = new ExtendedLdapAuthenticationProvider(authenticator, populator);
        override.setUserDetailProvider(userDetailProvider);

        beanFactory.registerSingleton(AUTHENTICATION_PROVIDER_BEAN, override);
    } else {
        throw new BeanCreationException("Could not find required beans to assemble overriding object for authentication...");
    }
}

现在我的问题是如何实现isWebSphere()方法。我在想Class.forName("someWebSphereSpecific"),但有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

ServletContext包含一个方法getServerInfo(),对于我的tomcat,它返回“Apache Tomcat / 6.0.13”。我假设webSphere将返回一些同样可区分的东西。

您唯一的问题是如何获取ServletContext。如果你在getServletConfig()下查找APIdoc索引,你会发现它可以从很多地方获得。如果您的servlet是由bean工厂创建的bean,那么您可以调用servletBean.getServletConfig().getServerInfo()

如果您创建的bean都没有为您提供访问权限,那么您可以创建一个纯粹用于执行此检测的虚拟servlet - 不是最好的,但它应该可以工作。

答案 1 :(得分:0)

根据约翰的建议,这是我的最终解决方案:

public class ServerInfoBeanOverrider implements BeanFactoryPostProcessor, ServletContextAware {
    private static final Log LOG = LogFactory.getLog(ServerInfoBeanOverrider.class);

    private String test;
    private Object overrideBean;
    private String overrideName;

    private String serverInfo;

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        if(LOG.isDebugEnabled()){
            LOG.debug("Testing if overriding is needed for server '"+serverInfo+"' with test pattern: " + test);
        }
        if(Pattern.matches(test, serverInfo)){
            if(LOG.isDebugEnabled()){
                LOG.debug("Overriding matched... replacing bean with name: " + overrideName);
            }
            beanFactory.registerSingleton(overrideName, overrideBean);
            LOG.info("Replaced bean with name: "+ overrideName + " for server: " + serverInfo);
        }
    }

    public void setServletContext(ServletContext servletContext) {
        this.serverInfo = servletContext.getServerInfo();
    }

    public void setOverrideBean(Object overrideBean) {
        this.overrideBean = overrideBean;
    }

    public void setOverrideName(String overrideName) {
        this.overrideName = overrideName;
    }

    public void setTest(String test) {
        this.test = test;
    }
}

这将允许基于匹配或不匹配正则表达式的服务器信息字符串覆盖bean。

它的用法如下:

  <!-- Replace with Tomcat's version if not running on WebSphere -->
  <bean class="some.company.web.util.ServerInfoBeanOverrider">
    <property name="test" value="Apache Tomcat/.*" />
    <property name="overrideName" value="authenticationProvider" />
    <property name="overrideBean">
      <bean class="some.company.providers.ExtendedLdapAuthenticationProvider" lazy-init="true">
        <constructor-arg ref="ldapAuthenticator" />
        <constructor-arg ref="ldapAuthoritiesPopulator" />
        <property name="userDetailProvider" ref="someUserDetailProvider" />
      </bean>
    </property>
  </bean>