《标记》-Spring的一些偏方

一、Environment和Profile的概念
Spring在容器中引入Environment和Profile的概念。每个应用程序上下文都有一个都可以访Environment对象。

ClassPathXmlApplicationContext classPathXmlApplicationContext = 
   new ClassPathXmlApplicationContext();
ConfigurableEnvironment configurableEnvironment = 
   classPathXmlApplicationContext.getEnvironment();
每种运行环境都有很多活动Profile类可供使用。大多数讲解Spring Profile的例子都是在开发模式或生产模式下。
对于不同运行环境问题来说,我的解决方案是使用使用多个Profile来适应不同运行时。
这个解决方案的优势是你可以自行决定如何使用Profile。

默认情况下,你所创建的Bean在载入容器中后是没有Profile对象的。
下面看一个例子。假设下面是我的应用程序中,数据源实例的定义。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="…">
<bean id="dataSource" destroy-method="close"
  class="org.apache.commons.dbcp.BasicDataSource">
  <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
  <property name="url" value="jdbc:hsqldb:hsql://localhost"/>
  <property name="username" value="sa"/>
  <property name="password" value=""/>
</bean>
</beans>
在Spring 3.0中,增加了一个新的容器类GenericXmlApplicationContext ,
可以作为ClassPathXmlApplicationContext和FileSystemXmlApplicationContext之外的另一个选择。
GenericXmlApplicationContext类的特点是可以通过Setter方法完成所有的配置,
而无需依靠笨重的构造器去完成配置。
记住,在初始化容器的准备工作完成后,需要调用refresh()方法完成实际的初始化工作。

下面的代码展示了如何使用GenericXmlApplicationContext类初始化容器:

GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
ctx.getEnvironment().setActiveProfiles("standalone");
ctx.load("*Context.xml");
ctx.refresh();

这里,我将活动Profile设置为“standalone”。
在这个工程里,
我希望代码既可以作为“standalone”运行在应用程序容器之外,
还可以作为“container”运行在容器中。
这里,我可以设置多个Profile,例如,下面的代码设置了Profile为“standalone”与“activemq”。

ctx.getEnvironment().setActiveProfiles("standalone", "activemq");
虽然做了上面的配置,实际上并不会对当前的配置上下文产生影响,
因为还没有配置Profile实例。所以,修改配置上下文为:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="…" profile="standalone">
 <bean id="dataSource" destroy-method="close"
  class="org.apache.commons.dbcp.BasicDataSource">
  <property name="driverClassName" value="org.hsqldb.jdbcDriver"/>
  <property name="url" value="jdbc:hsqldb:hsql://localhost"/>
  <property name="username" value="sa"/>
  <property name="password" value=""/>
</bean>
</beans>

只有当活动Profile设置为“standalone”时,才会实例化这个Bean。Profile是Bean的属性,而不是一个实例对象,因此,你无法配置单独的Bean来选择Profile。在较早的Spring版本中,
这会导致产生多个文件,而Ant的通配符无法在运行时找到正确的配置文件。
在Spring 3.1中,<beans/>标签可以嵌套在<beans/>标签内。现在,我们重新编写一下数据源配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="…">
<beans profile="standalone">  
<bean id="dataSource"> 
<property name="driverClassName" value="org.hsqldb.jdbcDriver"/> 
<property name="url" value="jdbc:hsqldb:hsql://localhost"/> 
<property name="username" value="sa"/> 
<property name="password" value=""/> 
</bean> 
</beans> 
 
<beans profile="container">
<jee:jndi-lookup id="dataSource" jndi-name="java:mydatasource"/>
</beans>
</beans>
这样,就可以通过下面的代码快速切换Profile:
ctx.getEnvironment().setActiveProfiles("container");
另一种切换Profile的方法是在运行时作为系统参数传入:
-Dspring.profiles.active="standalone"
此外,也可以作为Ear/War的初始化参数传入:

<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
  org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
  <param-name>spring.profiles.active</param-name>
  <param-value>production</param-value>
</init-param>
</servlet>

二、

IntrospectorCleanupListener简介

 
"在服务器运行过程中,Spring不停的运行的计划任务和OpenSessionInViewFilter,使得Tomcat反复加载对象而产生框架并用时可能产生的内存泄漏,则使用IntrospectorCleanupListener作为相应的解决办法。"
对于这一句话,引用关于IntrospectorCleanupListener一段解释:
引用
spring中的提供了一个名为org.springframework.web.util.IntrospectorCleanupListener的监听器。它主要负责处理由 JavaBeans Introspector的使用而引起的缓冲泄露。spring中对它的描述如下:它是一个在web应用关闭的时候,清除JavaBeans Introspector的监听器.web.xml中注册这个listener.可以保证在web 应用关闭的时候释放与掉这个web 应用相关的class loader 和由它管理的类如果你使用了JavaBeans Introspector来分析应用中的类,Introspector 缓冲中会保留这些类的引用.结果在你的应用关闭的时候,这些类以及web 应用相关的class loader没有被垃圾回收.不幸的是,清除Introspector的唯一方式是刷新整个缓冲.这是因为我们没法判断哪些是属于你的应用的引用.所以删除被缓冲的introspection会导致把这台电脑上的所有应用的introspection都删掉.需要注意的是,spring 托管的bean不需要使用这个监听器.因为spring它自己的introspection所使用的缓冲在分析完一个类之后会被马上从javaBeans Introspector缓冲中清除掉.应用程序中的类从来不直接使用JavaBeans Introspector.所以他们一般不会导致内部查看资源泄露.但是一些类库和框架往往会产生这个问题.例如:Struts 和Quartz.单个的内部查看泄漏会导致整个的web应用的类加载器不能进行垃圾回收.在web应用关闭之后,你会看到此应用的所有静态类资源(例如单例).这个错误当然不是由这个类自 身引起的.
用法很简单,就是在web.xml中加入:
<listener>
<listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
</listener>
只知道servlet标准不允许在web容器内自行做线程管理,quartz的问题确实存在。
对于Web容器来说,最忌讳应用程序私自启动线程,自行进行线程调度,像Quartz这种在web容器内部默认就自己启动了10线程进行异步job调度的框架本身就是很危险的事情,很容易造成servlet线程资源回收不掉,所以我一向排斥使用quartz。
quartz还有一个问题就是不支持cluster。导致使用quartz的应用都没有办法做群集。

三、Spring 多数据源扩展


在spring配置文件中配置N个datasource,并通过实现AbstractRoutingDataSource抽象类的子类进行多数据源的管理。

示例:
public class DatabaseContextHolder {  
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();  
    public static void setCustomerType(String customerType) {  
        contextHolder.set(customerType);  
    }  
  
    public static String getCustomerType() {  
        return contextHolder.get();  
    }  
  
    public static void clearCustomerType() {  
        contextHolder.remove();  
    }  
}  

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;  
public class DynamicDataSource extends AbstractRoutingDataSource{  
  
    @Override  
    protected Object determineCurrentLookupKey() {  
        return DatabaseContextHolder.getCustomerType();   
    }  
  
}

<bean id="dynamicDataSource" class="com.core.DynamicDataSource">  
        <property name="targetDataSources">  
            <map key-type="java.lang.String">  
                <entry value-ref="dataSourceOne" key="dataSourceOne"></entry>  
                <entry value-ref="dataSourceTwo" key="dataSourceTwo"></entry>  
            </map>  
        </property>  
        <property name="defaultTargetDataSource" ref="dataSourceOne">  
        </property>  
</bean>  

以后对Spring的一些特性,都在这个后面补充

参考:
http://howtodoinjava.com/spring/spring-orm/spring-3-2-5-abstractroutingdatasource-example/?utm_source=tuicool&utm_medium=referral
http://blog.sina.com.cn/s/blog_534f69a001013a20.html 
http://www.importnew.com/1099.html


评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值