Vincent

Vicent's blog
随笔 - 74, 文章 - 0, 评论 - 5, 引用 - 0
数据加载中……

Spring技巧之活用FactoryBean

Spring中有两种类型的Bean,一种是普通Bean,另一种是工厂Bean,即FactoryBean。工厂Bean跟普通Bean不同,其返回的对象不是指定类的一个实例,其返回的是该工厂Bean的getObject方法所返回的对象。在Spring框架内部,AOP相关的功能及事务处理中,很多地方使用到工厂Bean,本文简单分析工厂Bean的用法。
首先回顾一下普通Bean,普通的Bean直接返回指定类(配置中的class属性的值)的一个实例,如下面的bean1将返回一个String字符串:
<bean name="bean1" class="java.lang.String">
 
<constructor-arg value="我是字符串!" />
 
</bean> 

下面,看看一个简单的工厂Bean:
import java.util.Date;
import org.springframework.beans.factory.FactoryBean;
public class FactoryBeanDemo implements FactoryBean {
 
private String name;
 
public void setName(String name)
 {
  
this.name=name;
 }
 
public Object getObject() throws Exception {
  
if("date".equals(name))return new Date();
  
else return new String("这是一个字符串!");
 }
 
public Class getObjectType() {  
  
return "date".equals(name)?Date.class:String.class;
 }
 
public boolean isSingleton() {  
  
return false;
 }
}

下面看这个工厂Bean的配置:
<bean name="myFactoryBean" class="springroad.deomo.chap4.FactoryBeanDemo"/>
<bean name="myFactoryBean1" class="springroad.deomo.chap4.FactoryBeanDemo"><property name="name" value="date"/></bean>

下面是测试代码:
Resource res=new ClassPathResource("springroad/deomo/chap4/demo-bean.xml");
BeanFactory factory
=new XmlBeanFactory(res);
System.out.println(factory.getBean(
"myFactoryBean").getClass());
System.out.println(factory.getBean(
"myFactoryBean1").getClass());


输出结果:
class java.lang.String
class java.util.Date


由此可见,通过使用FactoryBean,我们可以得到不同类型的对象实例。这也就是我们在AOP中通过设置calss为 ProxyFactoryBean可以返回不同类型的业务对象的原理。在实际应用中若能灵活使用FactoryBean,则可以给应用程序增加很多的魔幻功能。

一个小窍门:
  FactoryBean还藏有一个技巧,也就是在我们实际需要返回FactoryBean实例时,应该怎么办。也就是我们在应用程序中需要通过容器得到一个FactoryBean。此时,需要使用特殊的方式,即在bean的名称前加上一个特殊符号“&”即可。
  如,下面的代码:
System.out.println(factory.getBean("&myFactoryBean").getClass());
 System.out.println(factory.getBean(
"&myFactoryBean1").getClass());

输出的结果将会是:
class  springroad.deomo.chap4.FactoryBeanDemo
class  springroad.deomo.chap4.FactoryBeanDemo 

posted @ 2006-08-22 09:52 Binary 阅读(261) | 评论 (0)编辑 收藏

Spring2.0中新的Bean类型实现原理

我们知道,在Spring2.0中,除了singleton及prototype两种类型的Bean以外。默认情况下还增加了request、 session及global session三种类型的Bean,增加的三种类型的Bean主要应用于Web应用程序中。本文不打算分析三种类型的 Bean的用法,只是简单分析框架的实现原理。
  Spring2.0中新增了一个用来表示Bean范围的Scope接口
  public interface Scope {
  Object get(String name, ObjectFactory objectFactory);
//根据名称及创建工厂得到一个Bean实例
  Object remove(String name);//删除一个指定名称的Bean
  }


  在容器ConfigurableBeanFactory接口中定义了Bean工厂有关Scope注册的相关方法,使得可往Bean工厂中加入新类型的Bean。
  public interface ConfigurableBeanFactory extends HierarchicalBeanFactory,
  
void registerScope(String scopeName, Scope scope);//往Bean工厂中添加一个新的范围(默认只有两种范围:singleton及prototype)
  void destroyScopedBean(String beanName);//销毁B ean工厂中范围Bean
  }


  在AbstractFactoryBean的getBean方法中实现了对特定Scope Bean支持,核心代码摘要:

    String scopeName = mergedBeanDefinition.getScope();//取得当前Bean的范围,也即在定义中的scope=”request”的部分。
    Scope scope = (Scope) this.scopes.get(scopeName);//得到Bean工厂中的范围处理器
    if (scope == null) {
     
throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");
    }
    
try {
//使用scope.get(beanName,ObjectFactory)从指定的范围中得到或创建Bean实例
     Object scopedInstance = scope.get(beanName, new ObjectFactory() {
      
public Object getObject() throws BeansException {
       beforePrototypeCreation(beanName);
//前拦截
       try {
        
return createBean(beanName, mergedBeanDefinition, args);//调用子类的createBean实现真正的Bean创建工作
       }
       
finally {
        afterPrototypeCreation(beanName);
//后拦截
       }
      }
     });
     bean 
= getObjectForBeanInstance(scopedInstance, name, mergedBeanDefinition);//返回正确类型的Bean实例
    }
    
catch (IllegalStateException ex) {
     
throw new BeanCreationException(beanName, "Scope '" + scopeName + "' is not active", ex);
    }


  默认情况下,低层的Bean工厂中只支持singleton及prototype两种类型的Bean。当把scope设置成request及 session时将会出现不能正确识别Scope的错误。这是因为普通的Bean工厂都没有注册新的Scope。只有在 WebApplicationContext中注册才注册了新类型的Bean。
  下面看实现注册Scope的代码:
  在WebApplicationContext中定义常量
public interface WebApplicationContext extends ApplicationContext {
  String SCOPE_REQUEST 
= "request";
  String SCOPE_SESSION 
= "session";
         String SCOPE_GLOBAL_SESSION 
= "globalSession";
}


  然后在所有类型的Web应用上下文的实现中,都在Bean工厂的拦载过程中通过postProcessBeanFactory方法来注册新类型 Scope,如GenericWebApplicationContext、StaticWebApplicationContext、
AbstractRefreshableWebApplicationContext等WebApplication应用上下文实现中。
  
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    beanFactory.registerScope(SCOPE_REQUEST, 
new RequestScope());//注册request类型的Bean
    beanFactory.registerScope(SCOPE_SESSION, new SessionScope(false));//注册session类型的Bean
    beanFactory.registerScope(SCOPE_GLOBAL_SESSION, new SessionScope(true));//注册glogalsession  的Bean
}


  结合上面的代码,现在应该明白为什么只有在Web应用上下文中才能使用新增加三种类型的Bean了吧。当然,由于有了Scope,我们也可以非常轻松的实现我们自己的Scope,增加新用户自定义类型的Bean,然后设计出一个适合我们自己的Bean工厂。

posted @ 2006-08-22 09:49 Binary 阅读(262) | 评论 (0)编辑 收藏

MYSQL的master/slave数据同步配置

我的测试环境.基本上数据是瞬间同步,希望对大家有帮助


redhat 9.0
mysql3.23.57



mysql数据同步备份


A服务器: 192.168.1.2 主服务器master
B服务器: 192.168.1.3 副服务器slave



A服务器设置


#mysql ?u root ?p
mysql>GRANT FILE ON *.* TO backup@192.168.1.3 IDENTIFIED BY ‘1234’;
mysql>\exit


上面是Master开放一个账号backup密码1234给IP:192.168.1.3有档案处理的权限



mysqladmin ?u root ?p shutdown


备份Master所有数据库..通常都用tar指令.
#tar ?cvf /tmp/mysql.tar /var/lib/mysql
注意:tar的时候,MySQL是要在stop情况下


在A机器上修改/etc/my.cnf
在[mysqld]区段内加入参数
log-bin
server-id=1
sql-bin-update-same
binlog-do-db=vbb


重启A服务器mysql


此时因为有加入log-bin参数,因此开始有index产生了,在/var/lib/mysql目录下有.index档案纪录数据库的异动log.



B服务器设置


设定/etc/my.cnf
在[mysqld]区段加入


master-host=192.168.1.2
master-user=backup
master-password=1234
master-port=3306
server-id=2
master-connect-retry=60 预设重试间隔60秒
replicate-do-db=vbb 告诉slave只做vbb数据库的更新
log-slave-updates



将A上的mysql.tar copy到B上
用ftp传B的/tmp
9.解压缩
#cd /var/lib/



状况测试
1.A跟B网络及服务都正常情况下,由A端变化数据后,到B端浏览数据,检视是否有进行replication?!
2.模拟B当机,或是B不一定需要一直跟A有连接.
将由A端变化数据后,到B端浏览数据,B点应该是没有数据变化的



#tar xvf /tmp/mysql-snapshot.tar
#chown ?R mysql:mysql mysql


1重启B服务器的mysql


这时在/var/lib/mysql目录会出现master.info,此档案纪录了Master MySQL server的信息.


?


状况测试
1.A跟B网络及服务都正常情况下,由A端变化数据后,到B端浏览数据,检视是否有进行replication?!
2.模拟B当机,或是B不一定需要一直跟A有连接.
将由A端变化数据后,到B端浏览数据,B点应该是没有数据变化的

posted @ 2006-08-22 09:43 Binary 阅读(219) | 评论 (0)编辑 收藏

加大MySQL的最大连接数

mysql的最大连接数默认是100, 这个数值对于并发连接很多的数据库应用是远远不够的,当连接请求大于默认连接数后,就会出现无法连接数据库的错误,因此我们需要把它适当调大一些,
有两种办法可以修改最大连接数,一种是修改safe_mysqld,另一种是直接修改原代码并重新编译。下面我们就分别介绍这两种方法:

1.修改safe_mysqld
找到safe_mysqld编辑它,找到mysqld启动的那两行,在后面加上参数 :

-O max_connections=1000


例如 :(其中前面有---的是原来的内容,而+++是修改过以后的)
--- safe_mysqld.orig Mon Sep 25 09:34:01 2000
+++ safe_mysqld Sun Sep 24 16:56:46 2000
@@ -109,10 +109,10 @@
if test "$#" -eq 0
then
nohup $ledir/mysqld --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR \
- --skip-locking >> $err_log 2>&1
+ --skip-locking -O max_connections=1000 >> $err_log 2>&1
else
nohup $ledir/mysqld --basedir=$MY_BASEDIR_VERSION --datadir=$DATADIR \
- --skip-locking "$@" >> $err_log 2>&1
+ --skip-locking "$@" -O max_connections=1000 >> $err_log 2>&1
fi
if test ! -f $pid_file # This is removed if normal shutdown
then
然后关闭mysql重启它,用
/mysqladmin所在路径/mysqladmin -uroot -p variables
输入root数据库账号的密码后可看到
| max_connections | 1000 |
即新改动已经生效。

2.修改原代码

解开MySQL的原代码,进入里面的sql目录修改mysqld.cc找到下面一行:

{ "max_connections", (long*) &max_connections,1000,1,16384,0,1},

把它改为:

{ "max_connections", (long*) &max_connections,1000,1,16384,0,1},

存盘退出,然后./configure make;make install可以获得同样的效果。

 

posted @ 2006-08-22 09:42 Binary 阅读(192) | 评论 (0)编辑 收藏

仅列出标题
共8页: 上一页 1 2 3 4 5 6 7 8