在struts2的action中注入了service的对象,service是用@Service("userService")注释进行实例化的,那实例化类型是不是必须为@Scope("prototype")这种类型,担心在struts2的多线程、多并发访问的时候在service类的方法中会导致数据混乱(请大家帮我解释一下这点);,因为struts2不是单例的,那是不是service类也必须要是@Scope("prototype"),这样为每个请求都重新创建一个service类的对象,这样才不致于在多线程情况下导致数据可能混乱呢??????
代码如下:
STRUTS2 Action类
public class UserAction extends BaseAction {
private static final long serialVersionUID = -2575509284575823496L;
@Resource(name = "userService")
private UserService userService;
private User user;
private List<Role> roleList;
public String add() throws Exception {
if (CollectionUtils.isEmpty(roleList)) {
addActionError("请选择角色");
return INPUT;
}
user.setRoleSet(new HashSet<Role>(roleList));
userService.createUser(user);
return SUCCESS;
}
}
SERVICE类:
@Scope("") ??????????????????? 这里什么时候用singleton 或者 prototype????????????????????????????????
@Service("userService")
public class UserServiceImpl extends PersistService implements UserService {
public void createUser(User user){
user.setPassword(MD5Utils.MD5Encode(user.getPassword()));
this.getJpaPersistence().persist(user);
}
}
在上面service类继承的PersistService 类中,也用spring注入了一个对数据库的通用的dao操作类(JpaPersistence jpaPersistence)
这样就可以在不同的service类中使用相同的dao操作类,这个通用的dao操作类是由spring的配置文件实例化的,配置如下:
那这个通用的dao操作类(JpaPersistence jpaPersistence)也就是singleton的,那这个通用的dao操作类在不同的service类中使用,会不会也像在STRUTS2的action中使用service类一样会导致数据混乱呢???
[quote]
2) 对于service层,我还是有点疑惑。
对于service类,你的意思是这样的嘛: service类中,一般就只是将传入的数据进行增、删、改、查,不会有对数据的修改,但我的理解是,service类就是业务逻辑类,业务流程全部封装在service类的方法中,是有可能对从action中传入的数据进行修改的,不然spring的事务控制加在service类的方法上就没有意义了,那事务控制就只能加在action的方法上了, 如果要在service类的方法中进行数据修改,service类默认又是singleton的,那从action中调用service类中的方法,就有可能出现数据混乱 ( 对这点很困惑,不知道是不是和php一样,相同的service类的对象,只要在调用其方法时就会开辟一个新栈,这样就不会有多线程不同步导致的数据混乱问题,还是说应该加入@Scope("prototype")避免其数据混乱 )
[/quote]
我说的service不用考虑并发问题,指的是Service对象本身,因为在JVM中对象是存储在堆上的,所以如果对象本事是有状态的,那么在并发请求下,这些属性有可能需要同步。但通常情况下,Spring里面的Service是完全无状态的,所以说Service本事是线程安全,并发请求不会有问题。
至于不同的action调用相同的service的同一方法的问题,那更不用担心,因为java的方法调用是基于栈的,这些栈都是线程独立的,所以每次action调用servcie的方法时,其实都是在独立的环境中,即时传入的对象参数是一样的,那也只能到最终保持到数据库时考虑数据的一致性,这个是后面的事务问题了。
整个过程中,最需要考虑并发的是数据库,因为所以的CRUD操作最终都会落实到数据库上,而每个数据记录又都和实体对象对应,所以只有在数据操作时需要考虑并发问题,但这个问题已经由数据库和hibernate完成了,spring里面设置的事务配置其实也是依赖于底层的数据库事务,事务的隔离级别就告诉你了,数据库的操作在什么样的情况下不会出现并发问题。具体的每个事务隔离级别代表的含义,你可以查查。
首先你需要明白,之所以并发会出现数据同步问题的话,那是因为对象本身是有状态的。在SSH这样的环境中,Struts的Action是有状态的(它有很多属性),但它并不需要考虑并发问题,因为struts2里的action对象是每次请求创建的(使用spring创建时,指定prototype也是这个目的),这点和struts1不一样,所以不存在属性会被并发访问的问题。
spring默认的创建对象都是单例的(在同一个上下文是这样),所以有可能需要在并发是考虑同步问题。但具体到Service来说,通常我们的Service没有任何状态,完全是方法的集合,所以即使通过单例形式注入到action中后,在调用的过程中也不用考虑并发的问题。
至于dao,也是类似的道理,但针对数据库的连接是有并发问题的,不过,在你使用spring时,这个问题spring也已经考虑到了,对于这样有状态对象的注入,spring通常会把当前对象和其线程绑定,比如通过ThreadLocal。