`
卡拉阿风
  • 浏览: 101243 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

由单点登陆引发的问题(二):用户数据同步

阅读更多
用户数据同步:A系统在自己的数据库里有用户数据表,B系统在自己的数据库里有用户数据表,即他们相互独立。现在要求他们表里的用户名和密码能保持同步。A系统w r,B系统r;在A系统中进行用户的CRUD。B系统用户数据必须进行同步的CRUD。

针对这个场景,立哥给我提出了2个思路。
实时性要求比较高的: 
*A系统w,发送一条mq消息。B系统监听mq,收到消息,做单条数据同步   
实时行要求不高的: 
*可以考虑数据库同步--定时任务

由于用户在2个系统里来回浏览相对频繁,实时性要求较高。我们都偏向于第一个思路。

原先我打算采用httpclient。
即在A系统修改用户数据,通过httpclient来对B系统的进行操作。即按照传统的思想同步操作,但这样又带来了一个问题:增加了A系统和B系统的耦合度。

考虑异步方式:JMS (ActiveMQ)
引用

JMS
* 它可以把不影响用户执行结果又比较耗时的任务(比如发邮件通知管理员)异步的扔给JMS 服务端去做,而尽快的把屏幕返还给用户。
* 服务端能够多线程排队响应高并发的请求,并保证请求不丢失。
* 可以在Java世界里达到最高的解耦。客户端与服务端无需直连,甚至无需知晓对方是谁、在哪里、有多少人,只要对流过的信息作响应就行了,在企业应用环境复杂时作用明显。

ActiveMQ的特性:
* 完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,也是Apache Geronimo默认的JMS provider。
* POJO withdout EJB Container,不需要实现EJB繁琐复杂的Message Bean接口和配置。
* Spring Base,可以使用Spring的各种特性如IOC、AOP 。
* Effective,基于Jencks的JCA Container实现 pool connection,control transactions and manage security。


JMS两种实现方法
Topic==>消息主题     是发布/订阅机制 一个消息产生多个对应 1:N 
Queue==>消息队列     是点到点机制    一个消息产生一个对应 1:1 

无论采用哪种实现方式,在两个系统中,对应的physicalName必须相同,这样才能接收到消息。

JMS消息类型
1.使用 TextMessage 类
2.使用 BytesMessage 类
3.使用映射消息
4.使用流消息
5.使用对象消息

我采用的是第5种,注意对象必须实现java.io.Serializable接口,不然会抛出java.io.InvalidClassException。在A和B系统中的两个POJO必须完全一样,serialVersionUID也一样。

使用JMS集成两个应用,需要两个应用连接同一个jms server。
所以首先要确保B应用连接到A应用启动的embedded ActiceMQ。
<!--  embedded ActiveMQ Broker -->
	<amq:broker useJmx="false" persistent="true">
		<amq:persistenceAdapter>
			<amq:amqPersistenceAdapter directory="/home/dylan/JavaPro/amq"/>
		</amq:persistenceAdapter> 
		<amq:transportConnectors>
			<amq:transportConnector uri="tcp://localhost:61616" />
		</amq:transportConnectors>
	</amq:broker>
	
	  ActiveMQ connectionFactory  -->
	<!--连接自己的activeMQ -->
	<amq:connectionFactory id="jmsConnectionFactory" brokerURL="vm://localhost" />


<amq:connectionFactory id="jmsConnectionFactory" brokerURL="tcp://localhost:61616" />


关于ActiveMQ,可以参考
Apache ActiveMQ > Using ActiveMQ > Xml Reference > XBean XML Reference 5.0
http://activemq.apache.org/xbean-xml-reference-50.html#XBeanXMLReference5.0-connectionFactoryelement

ActiveMQ5.0实战一、二、三
http://www.iteye.com/topic/153171

引用来自:ActiveMQ4.1 +Spring2.0的POJO JMS方案
http://wiki.springside.org.cn/display/springside/ActiveMQ
分享到:
评论
23 楼 卡拉阿风 2010-03-01  
saiskysky 写道
jmsConnectionFactory
卡拉阿风 写道
saiskysky 写道

因为我希望能够在每个系统里通过其注册方法注册,然后调用其他的系统的注册接口同步注册,如果这样的话增加删除一个系统,都需要在其他系统的注册方法里面修改调用咯。


又不用的。。本来就没有耦合性
消息广播之后它是不管结果的。
你删除系统,这个时候就不会监听到消息,对监听的系统本身也没什么影响
你增加系统,只要在广播消息的时候,名字和监听的时候名字是一样的就可以了。这个时候也不需要对原有的系统进行任何修改。
当然系统本身很少会这么麻烦,但我们不排除它存在的可能性,这个时候CAS就是一个不错的选择。

提到cas,想问下,我是想用cas做单点登录功能的,我的思路是:当进入一个子系统,先查看cas是否已登录,如果登录,就获取登录loginname,然后经过一个用于自动登录的过滤器将信息查询出来后放进该子系统里面的登录session,达到单点登录的效果。
网上有教配置如下:
<filter>
        <filter-name>CASFilter</filter-name>
        <filter-class>edu.yale.its.tp.cas.client.filter.CASFilter</filter-class>
        <init-param>
        <param-name>edu.yale.its.tp.cas.client.filter.loginUrl</param-name>
        <param-value>https://localhost:8443/cas/login</param-value>
        </init-param>
        <init-param>
        <param-name>edu.yale.its.tp.cas.client.filter.validateUrl</param-name>
        <param-value>https://localhost:8443/cas/proxyValidate</param-value>
        </init-param>
        <init-param>
        <param-name>edu.yale.its.tp.cas.client.filter.serverName</param-name>
        <param-value>localhost:8080</param-value> -->
</init-param>
    </filter>

    <filter-mapping>
        <filter-name>CASFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

这种配置是拦截所有的网页和action的操作,一进入系统就要先登录,但实际上网站有部分网页是不需要登录就可以直接使用的,如果在/*这里改为需要拦截的那些网页地址,因为不被拦截的那些网页又有引用到登录的session,例如有“欢迎***进入”,由于不经过cas的拦截,自动登录的过滤器无法获取到cas的登录loginname,这样就显示不出“欢迎***进入”这句话。

那么请问需要改动什么地方才能达到我想要的效果呢??
我曾想过将上面的配置复制一次然后改过滤器的名称,然后这个过滤器不配置登录
<init-param>
        <param-name>edu.yale.its.tp.cas.client.filter.loginUrl</param-name>
        <param-value>https://localhost:8443/cas/login</param-value>
        </init-param>
这个配置,但是会显示出错,应该这种方法是不可行的。那么我要怎么做呢??谢谢

cas我只是简单测试过。没有做多大的深入了解。

在应用中,获取用户名
在jsp代码中,加入以下代码即可。
session.getAttribute(CASFilter.CAS_FILTER_USER);
session.getAttribute("edu.yale.its.tp.cas.client.filter.user");

22 楼 saiskysky 2010-03-01  
jmsConnectionFactory
卡拉阿风 写道
saiskysky 写道

因为我希望能够在每个系统里通过其注册方法注册,然后调用其他的系统的注册接口同步注册,如果这样的话增加删除一个系统,都需要在其他系统的注册方法里面修改调用咯。


又不用的。。本来就没有耦合性
消息广播之后它是不管结果的。
你删除系统,这个时候就不会监听到消息,对监听的系统本身也没什么影响
你增加系统,只要在广播消息的时候,名字和监听的时候名字是一样的就可以了。这个时候也不需要对原有的系统进行任何修改。
当然系统本身很少会这么麻烦,但我们不排除它存在的可能性,这个时候CAS就是一个不错的选择。

提到cas,想问下,我是想用cas做单点登录功能的,我的思路是:当进入一个子系统,先查看cas是否已登录,如果登录,就获取登录loginname,然后经过一个用于自动登录的过滤器将信息查询出来后放进该子系统里面的登录session,达到单点登录的效果。
网上有教配置如下:
<filter>
        <filter-name>CASFilter</filter-name>
        <filter-class>edu.yale.its.tp.cas.client.filter.CASFilter</filter-class>
        <init-param>
        <param-name>edu.yale.its.tp.cas.client.filter.loginUrl</param-name>
        <param-value>https://localhost:8443/cas/login</param-value>
        </init-param>
        <init-param>
        <param-name>edu.yale.its.tp.cas.client.filter.validateUrl</param-name>
        <param-value>https://localhost:8443/cas/proxyValidate</param-value>
        </init-param>
        <init-param>
        <param-name>edu.yale.its.tp.cas.client.filter.serverName</param-name>
        <param-value>localhost:8080</param-value> -->
</init-param>
    </filter>

    <filter-mapping>
        <filter-name>CASFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

这种配置是拦截所有的网页和action的操作,一进入系统就要先登录,但实际上网站有部分网页是不需要登录就可以直接使用的,如果在/*这里改为需要拦截的那些网页地址,因为不被拦截的那些网页又有引用到登录的session,例如有“欢迎***进入”,由于不经过cas的拦截,自动登录的过滤器无法获取到cas的登录loginname,这样就显示不出“欢迎***进入”这句话。

那么请问需要改动什么地方才能达到我想要的效果呢??
我曾想过将上面的配置复制一次然后改过滤器的名称,然后这个过滤器不配置登录
<init-param>
        <param-name>edu.yale.its.tp.cas.client.filter.loginUrl</param-name>
        <param-value>https://localhost:8443/cas/login</param-value>
        </init-param>
这个配置,但是会显示出错,应该这种方法是不可行的。那么我要怎么做呢??谢谢
21 楼 卡拉阿风 2010-03-01  
saiskysky 写道

因为我希望能够在每个系统里通过其注册方法注册,然后调用其他的系统的注册接口同步注册,如果这样的话增加删除一个系统,都需要在其他系统的注册方法里面修改调用咯。


又不用的。。本来就没有耦合性
消息广播之后它是不管结果的。
你删除系统,这个时候就不会监听到消息,对监听的系统本身也没什么影响
你增加系统,只要在广播消息的时候,名字和监听的时候名字是一样的就可以了。这个时候也不需要对原有的系统进行任何修改。
当然系统本身很少会这么麻烦,但我们不排除它存在的可能性,这个时候CAS就是一个不错的选择。
20 楼 saiskysky 2010-03-01  
卡拉阿风 写道
saiskysky 写道

看来前期设计是相当重要的,我考虑使用什么设计模式整整用了两个月还在考虑当中啊,郁闷死了。如果使用webservice的方法,改动的好像更大,每个系统都要变为webservice系统,然后各自提供出注册方法供另外的系统使用,这样耦合度比这个更高了。

最重要是我没法解决如果其中一个注册失败的情况,要怎么做才能让他自己重新注册呢??如果异步的方式是没法管到的,请问有没有什么好的方法呢??谢谢提示啊 

然后各自提供出注册方法供另外的系统使用
这个是什么意思?
每个系统的注册模块都是单独的,供自己系统使用的,怎么会增加耦合度?

简单的方法可以使用cas-中央认证系统
网上有很多教程,你可以参考下。
其实我这里的设计是最简单的了。

因为我希望能够在每个系统里通过其注册方法注册,然后调用其他的系统的注册接口同步注册,如果这样的话增加删除一个系统,都需要在其他系统的注册方法里面修改调用咯。

19 楼 卡拉阿风 2010-03-01  
saiskysky 写道

看来前期设计是相当重要的,我考虑使用什么设计模式整整用了两个月还在考虑当中啊,郁闷死了。如果使用webservice的方法,改动的好像更大,每个系统都要变为webservice系统,然后各自提供出注册方法供另外的系统使用,这样耦合度比这个更高了。

最重要是我没法解决如果其中一个注册失败的情况,要怎么做才能让他自己重新注册呢??如果异步的方式是没法管到的,请问有没有什么好的方法呢??谢谢提示啊 

然后各自提供出注册方法供另外的系统使用
这个是什么意思?
每个系统的注册模块都是单独的,供自己系统使用的,怎么会增加耦合度?

简单的方法可以使用cas-中央认证系统
网上有很多教程,你可以参考下。
其实我这里的设计是最简单的了。
18 楼 saiskysky 2010-03-01  
卡拉阿风 写道
saiskysky 写道
我想了很长时间,觉得这种整合方法好像有个问题,如果我整合的系统不断增加的情况下,userinfo 对象是否就需要每个系统都修改一遍吗??这样会容易出现漏修改的情况的哦??

是这样的。你能想到这个很好
怎么使项目的设计合理,同时是否过度优化。。。
如果项目需要经常变动,你可以引入相关的设计模式进行合理设计,以防系统修改带来的麻烦。

看来前期设计是相当重要的,我考虑使用什么设计模式整整用了两个月还在考虑当中啊,郁闷死了。如果使用webservice的方法,改动的好像更大,每个系统都要变为webservice系统,然后各自提供出注册方法供另外的系统使用,这样耦合度比这个更高了。

最重要是我没法解决如果其中一个注册失败的情况,要怎么做才能让他自己重新注册呢??如果异步的方式是没法管到的,请问有没有什么好的方法呢??谢谢提示啊 
17 楼 卡拉阿风 2010-03-01  
saiskysky 写道
我想了很长时间,觉得这种整合方法好像有个问题,如果我整合的系统不断增加的情况下,userinfo 对象是否就需要每个系统都修改一遍吗??这样会容易出现漏修改的情况的哦??

是这样的。你能想到这个很好
怎么使项目的设计合理,同时是否过度优化。。。
如果项目需要经常变动,你可以引入相关的设计模式进行合理设计,以防系统修改带来的麻烦。
16 楼 saiskysky 2010-03-01  
我想了很长时间,觉得这种整合方法好像有个问题,如果我整合的系统不断增加的情况下,userinfo 对象是否就需要每个系统都修改一遍吗??这样会容易出现漏修改的情况的哦??
15 楼 卡拉阿风 2010-02-27  
saiskysky 写道
卡拉阿风 写道
saiskysky 写道
请问为什么在传对象消息的时候,我使用的是message.setObjectProperty(),将用户信息bean对象放进object的位置,但是抛出异常为:
javax.jms.MessageFormatException: Only objectified primitive objects, String, Map and List types are allowed but was:userinfo
是什么原因呢??

这个问题我也没有碰到过
你看看这里http://www.iteye.com/topic/153171
希望对你有所帮助

改用message.setObject(Object);这个方法就可以传了,但具体原因我觉得可能是序列化的问题吧,可是我的传的Object是有继承Serializable的,真是不知道为什么呢??

userinfo 在两个系统的文件要一模一样,你最好完全复制过来。包括serialVersionUID
14 楼 saiskysky 2010-02-27  
卡拉阿风 写道
saiskysky 写道
请问为什么在传对象消息的时候,我使用的是message.setObjectProperty(),将用户信息bean对象放进object的位置,但是抛出异常为:
javax.jms.MessageFormatException: Only objectified primitive objects, String, Map and List types are allowed but was:userinfo
是什么原因呢??

这个问题我也没有碰到过
你看看这里http://www.iteye.com/topic/153171
希望对你有所帮助

改用message.setObject(Object);这个方法就可以传了,但具体原因我觉得可能是序列化的问题吧,可是我的传的Object是有继承Serializable的,真是不知道为什么呢??
13 楼 卡拉阿风 2010-02-26  
saiskysky 写道
请问为什么在传对象消息的时候,我使用的是message.setObjectProperty(),将用户信息bean对象放进object的位置,但是抛出异常为:
javax.jms.MessageFormatException: Only objectified primitive objects, String, Map and List types are allowed but was:userinfo
是什么原因呢??

这个问题我也没有碰到过
你看看这里http://www.iteye.com/topic/153171
希望对你有所帮助
12 楼 saiskysky 2010-02-26  
请问为什么在传对象消息的时候,我使用的是message.setObjectProperty(),将用户信息bean对象放进object的位置,但是抛出异常为:
javax.jms.MessageFormatException: Only objectified primitive objects, String, Map and List types are allowed but was:userinfo
是什么原因呢??
11 楼 卡拉阿风 2010-02-26  
saiskysky 写道

非常感谢您的耐心教导,也解决到整合的问题了,不过是否有更好的整合方式呢??
不过想问个题外的问题,我曾考虑过从数据库层面入手做映射,但是寻找不到合适的技术支持,只能通过代码层面做整合,不知道是否有更好的整合方式呢??
谢谢了

具体场景具体分析
实时性要求比较高的:
*JMS
实时行要求不高的:
*可以考虑数据库同步--定时任务

数据库层面入手做映射 是指 两个数据库产生关联?
这样就增加了耦合度了。
10 楼 saiskysky 2010-02-26  
卡拉阿风 写道
saiskysky 写道
再请教个问题可以吗??对象消息传递的是什么东西呢??是否可以用来传递一个bean呢??那么它的创建方式是怎样的呢??是否和TextMessage 一样呢??

对象消息传递就是消息传递的是对象
是否可以用来传递一个bean呢??
可以
那么它的创建方式是怎样的呢??是否和TextMessage 一样呢??
都是消息创造者产生的。
TextMessage 只是一个消息类型。所以是一样的。

非常感谢您的耐心教导,也解决到整合的问题了,不过是否有更好的整合方式呢??
不过想问个题外的问题,我曾考虑过从数据库层面入手做映射,但是寻找不到合适的技术支持,只能通过代码层面做整合,不知道是否有更好的整合方式呢??
谢谢了
9 楼 卡拉阿风 2010-02-25  
saiskysky 写道
再请教个问题可以吗??对象消息传递的是什么东西呢??是否可以用来传递一个bean呢??那么它的创建方式是怎样的呢??是否和TextMessage 一样呢??

对象消息传递就是消息传递的是对象
是否可以用来传递一个bean呢??
可以
那么它的创建方式是怎样的呢??是否和TextMessage 一样呢??
都是消息创造者产生的。
TextMessage 只是一个消息类型。所以是一样的。
8 楼 saiskysky 2010-02-25  
再请教个问题可以吗??对象消息传递的是什么东西呢??是否可以用来传递一个bean呢??那么它的创建方式是怎样的呢??是否和TextMessage 一样呢??
7 楼 saiskysky 2010-02-25  
卡拉阿风 写道
saiskysky 写道
那么想请教下,我的项目是ssh框架的,我在监听方那端的,当onMessage中收到通知后,调用了biz层的插入方法,用断点测试后是可以进入该方法,但无法执行到相应的hql语句(插入方法本身无问题,在action层是可以正常使用的),请问是什么原因呢??调用biz层的查询方法却是可以正常使用的。请问您当时是怎么处理这个问题的呢??谢谢啊

但无法执行到相应的hql语句
这个只能你自己debug了。然后根据提示信息做相应的修改。

我已经解决了,是session冲突,改用另外的插入方式就可以了
6 楼 卡拉阿风 2010-02-25  
saiskysky 写道
那么想请教下,我的项目是ssh框架的,我在监听方那端的,当onMessage中收到通知后,调用了biz层的插入方法,用断点测试后是可以进入该方法,但无法执行到相应的hql语句(插入方法本身无问题,在action层是可以正常使用的),请问是什么原因呢??调用biz层的查询方法却是可以正常使用的。请问您当时是怎么处理这个问题的呢??谢谢啊

但无法执行到相应的hql语句
这个只能你自己debug了。然后根据提示信息做相应的修改。
5 楼 saiskysky 2010-02-25  
那么想请教下,我的项目是ssh框架的,我在监听方那端的,当onMessage中收到通知后,调用了biz层的插入方法,用断点测试后是可以进入该方法,但无法执行到相应的hql语句(插入方法本身无问题,在action层是可以正常使用的),请问是什么原因呢??调用biz层的查询方法却是可以正常使用的。请问您当时是怎么处理这个问题的呢??谢谢啊
4 楼 卡拉阿风 2010-02-24  
saiskysky 写道
卡拉阿风 写道
saiskysky 写道
那请问如果有三个系统呢,也是这样做吗??

JMS采用topic

请问是否意思是当我其中一个系统中修改了数据,然后通知JMS 服务端,然后JMS会自动帮忙通知另外的系统做修改呢??有个问题是,如果两个系统的用户表信息均不同,那么需要怎么做比较好呢??(例如: 一个表里面信息有用户名,密码,邮箱,地址;另一个表信息:用户名,密码,邮箱,电话,如果修改的是邮箱,那么两个表都需要修改,但修改的是电话,另一个表也要做修改吗??)请指教,谢谢

JMS两种实现方法
Topic==>消息主题     是发布/订阅机制 一个消息产生多个对应 1:N
Queue==>消息队列     是点到点机制    一个消息产生一个对应 1:1 

JMS不是自动帮忙通知另外的系统做修改,当其中一个系统中修改了数据,服务端只负责广播消息,而不管结果,而客户端对消息进行监听,当监听到广播后再进行相关操作。
你的场景,可以采用同一条消息,也可以采用不同的消息

相关推荐

Global site tag (gtag.js) - Google Analytics