spring @Transactional注解参数详解

 spring  spring @Transactional注解参数详解已关闭评论
2月 072018
 

写的比较清楚,来自:https://www.cnblogs.com/caoyc/p/5632963.html

事物注解方式: @Transactional

当标于类前时, 标示类中所有方法都进行事物处理 , 例子:

1 @Transactional public class TestServiceBean implements TestService {}

当类中某些方法不需要事物时:

@Transactional  
public class TestServiceBean implements TestService { 
    private TestDao dao; 
    public void setDao(TestDao dao) { 
        this.dao = dao; 
    } 
    @Transactional(propagation =Propagation.NOT_SUPPORTED)
    public List getAll() { 
        return null; 
    } 
}

事物传播行为介绍: 

@Transactional(propagation=Propagation.REQUIRED) :如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
@Transactional(propagation=Propagation.NOT_SUPPORTED) :容器不为这个方法开启事务
@Transactional(propagation=Propagation.REQUIRES_NEW) :不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
@Transactional(propagation=Propagation.MANDATORY) :必须在一个已有的事务中执行,否则抛出异常
@Transactional(propagation=Propagation.NEVER) :必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS) :如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.

 

事物超时设置:

@Transactional(timeout=30) //默认是30秒

 

事务隔离级别:

@Transactional(isolation = Isolation.READ_UNCOMMITTED):读取未提交数据(会出现脏读, 不可重复读) 基本不使用
@Transactional(isolation = Isolation.READ_COMMITTED):读取已提交数据(会出现不可重复读和幻读)
@Transactional(isolation = Isolation.REPEATABLE_READ):可重复读(会出现幻读)
@Transactional(isolation = Isolation.SERIALIZABLE):串行化

MYSQL: 默认为REPEATABLE_READ级别
SQLSERVER: 默认为READ_COMMITTED

脏读 : 一个事务读取到另一事务未提交的更新数据
不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说, 
后续读取可以读到另一事务已提交的更新数据. 相反, “可重复读”在同一事务中多次
读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
幻读 : 一个事务读到另一个事务已提交的insert数据

 

@Transactional注解中常用参数说明

参数名称

功能描述

readOnly

该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)

rollbackFor

该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:

指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

rollbackForClassName

该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:

指定单一异常类名称:@Transactional(rollbackForClassName=”RuntimeException”)

指定多个异常类名称:@Transactional(rollbackForClassName={“RuntimeException”,”Exception”})

noRollbackFor

该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:

指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})

noRollbackForClassName

该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:

指定单一异常类名称:@Transactional(noRollbackForClassName=”RuntimeException”)

指定多个异常类名称:

@Transactional(noRollbackForClassName={“RuntimeException”,”Exception”})

propagation

该属性用于设置事务的传播行为,具体取值可参考表6-7。

例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

isolation

该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置

timeout

该属性用于设置事务的超时秒数,默认值为-1表示永不超时

 

 

注意的几点:


1、@Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
2、用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException(“注释”);)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new Exception(“注释”);)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
如下:

复制代码
1 @Transactional(rollbackFor=Exception.class) //指定回滚,遇到异常Exception时回滚 2 public void methodName() { 3 throw new Exception("注释"); 4 } 5 @Transactional(noRollbackFor=Exception.class)//指定不回滚,遇到运行期例外(throw new RuntimeException("注释");)会回滚 6 public ItimDaoImpl getItemDaoImpl() { 7 throw new RuntimeException("注释"); 8 }
复制代码

3、@Transactional 注解应该只被应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。


4、@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 元素的出现 开启 了事务行为。


5、Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是不能继承的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因此,请接受Spring团队的建议并且在具体的类上使用 @Transactional 注解。

Spring注解@Component、@Repository、@Service、@Controller @Resource、@Autowired、@Qualifier 解析

 java, spring  Spring注解@Component、@Repository、@Service、@Controller @Resource、@Autowired、@Qualifier 解析已关闭评论
1月 102017
 

这篇文章解释的很清楚http://www.ulewo.com/user/10001/blog/273,记录下:

我们在使用spring的时候经常会用到这些注解,那么这些注解到底有什么区别呢。我们先来看代码

同样分三层来看:

Action 层:

package com.ulewo.ioc; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; @Controller public class IocAction {
    @Autowired     private IocService service;
    
    public void add(){
        service.add();
    }
}

service层:(service就直接定义类了,没有定义接口,定义接口也是一样的)

package com.ulewo.ioc; import javax.annotation.Resource; import org.springframework.stereotype.Service; @Service public class IocService {
    @Resource     private IIocDao iocDao;
    public void add(){
        iocDao.add();
    }
}

Dao层

先定义一个接口

package com.ulewo.ioc; public interface IIocDao {
    public void add();
}

然后实现类:

package com.ulewo.ioc; import org.springframework.stereotype.Repository; @Repository public class IocDao implements IIocDao{
    public void add(){
        System.out.println("调用了dao");
    }
}

然后spring的配置,这个配置就很简单了,因为是基于注解的,我们不需要再xml中来定义很多

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>   <beans xmlns="http://www.springframework.org/schema/beans"    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xmlns:jee="http://www.springframework.org/schema/jee"    xmlns:tx="http://www.springframework.org/schema/tx"    xmlns:context="http://www.springframework.org/schema/context"    xmlns:aop="http://www.springframework.org/schema/aop"    xmlns:task="http://www.springframework.org/schema/task"    xsi:schemaLocation="http://www.springframework.org/schema/beans 
                       http://www.springframework.org/schema/beans/spring-beans-3.2.xsd 
                       http://www.springframework.org/schema/tx 
                       http://www.springframework.org/schema/tx/spring-tx-3.2.xsd 
                       http://www.springframework.org/schema/jee 
                       http://www.springframework.org/schema/jee/spring-jee-3.2.xsd 
                       http://www.springframework.org/schema/context 
                       http://www.springframework.org/schema/context/spring-context-3.2.xsd
                       http://www.springframework.org/schema/aop 
                       http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
                       http://www.springframework.org/schema/task 
                       http://www.springframework.org/schema/task/spring-task-3.2.xsd">     <context:annotation-config />         <context:component-scan base-package="com.ulewo.ioc" >     </context:component-scan>   </beans>

让spring自动扫描包就行了。

然后是我们的测试类:

IocTest:

package com.ulewo.ioc; import junit.framework.TestCase; import org.springframework.beans.factory.BeanFactory; import org.springframework.context.support.ClassPathXmlApplicationContext; public class IocTest extends TestCase{
    
    public void testIoc(){
        BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
        IocAction action = factory.getBean("iocAction", IocAction.class);
        action.add();
    }
}

运行后,我们会发现 控制台打印:调用了dao

@Component、@Repository、@Service、@Controller @Resource、@Autowired、@Qualifier 

这几个基本都用到了 除了 @Component  @Qualifier

我们观察会发现@Repository、@Service、@Controller 这几个是一个类型,其实@Component 跟他们也是一个类型的

Spring 2.5 中除了提供 @Component 注释外,还定义了几个拥有特殊语义的注释,它们分别是:@Repository、@Service和 @Controller 其实这三个跟@Component 功能是等效的

@Service用于标注业务层组件(我们通常定义的service层就用这个)

@Controller用于标注控制层组件(如struts中的action)

@Repository用于标注数据访问组件,即DAO组件

@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

这几个注解是当你需要定义某个类为一个bean,则在这个类的类名前一行使用@Service(“XXX”),就相当于讲这个类定义为一个bean,bean名称为XXX; 这几个是基于类的,我们可以定义名称,也可以不定义,不定义会默认以类名为bean的名称(类首字母小写)。

然后我们在看后面的几个注解

@Resource、@Autowired、@Qualifier

当需要在某个类中定义一个属性,并且该属性是一个已存在的bean,要为该属性赋值我们就用着三个。我们看上面的代码可以看到这三个都是定义在一个属性上的,比如

@Resource private IIocDao iocDao;
@Autowired private IocService service;

那这几个到底有什么区别呢?

我们先看@Resource,它是javax.annotation.Resource; 这个包中,也就是说是javaEE中的,并不是spring中的

而且@Resource(“xxx”) 是可以定义bean名称的,就是说我这个属性要用那个bean来赋值。

@Autowired,它是org.springframework.beans.factory.annotation.Autowired 是这个包中,它是spring的包。

而且它没有@Autowired(“xxx”),那我要为这个bean定义名称怎么办这个时候可以用@Qualifier(“xxx”) 这个也是spring中的。这个xxx定义bean名称有什么用呢?我们回头看下刚才的代码。

在IIocDao 这个接口中,我们定义的实现类IocDao 只有一个,好那么我们再定义一个实现类:

package com.ulewo.ioc; import org.springframework.stereotype.Repository; @Repository public class IocDao2 implements IIocDao{
    public void add(){
        System.out.println("调用了dao2");
    }
}

其他不变,我们再运行:testIoc(),控制台打印出 调用了dao,所以在service层中

@Resource
private IIocDao iocDao;

这个iocDao 注入的是IocDao 这个实现。奇怪了,它怎么知道我要调用哪个实现呢?

好我们修改一下,把 private IIocDao iocDao;改一下,改成 private IIocDao iocDaox 把属性名改一下,再运行,会报错:

org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.ulewo.ioc.IIocDao] is defined: expected single matching bean but found 2: iocDao,iocDao2

错误很明显啊,有两个bean iocDao和iocDao2,但是我们的是iocDaox所以找不到了。所以可以看出来在用 @Repository注解来生成bean的时候,如果没有定义名称那么就会根据类名来生成。所以我们要调用第二个实现的时候可以 定义为private IIocDao iocDao2 。我们再运行:调用了dao2,所以可以根据属性名来区分,到底注入那个bean。但是有的人说,我不想定义bean名称跟类实现一样,我要定义其他的,那怎么玩呢,方法有2种:

第一种:我们在生成bean的时候就给bean定义个名称 

@Repository(“myIocDao”)
public class IocDao implements IIocDao{
    public void add(){
        System.out.println(“调用了dao”);
    }
}

当然@Service是一样的,这样就把这个实现定义为myIocDao了,而不是默认的类名 iocDao。

那么我们在使用这个bean的时候就要这么定义了:

@Resource
private IIocDao myIocDao;

运行 输出:调用了dao

如果你这里不是用的 myIocDao,你又多加了一个x,成了myIocDaox,你运行会是这样的:

 org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [com.ulewo.ioc.IIocDao] is defined: expected single matching bean but found 2: myIocDao,iocDao2

所以,要自定义bean的名称可以在类注解的时候指定。

第二种:在注入bean的时候指定名称:

先看@Resource

我们这么定义下:

@Resource(name=”iocDao”)
private IIocDao xx;

注意:

@Repository
public class IocDao implements IIocDao{
    public void add(){
        System.out.println(“调用了dao”);
    }
}

这里还是用会默认的,也就是这个实现对应的是 iocDao这bean。如果你要为这个类指定别名bean,@Repository(“myIocDao”),那@Resource(name=”myIocDao”) 就要这么写了。就是这里的name要跟实现类对应的bean名称保持一致。private IIocDao xx; 这个属性名就随便写了。

运行:调用了dao

如果用Autowired就要这么写了

@Autowired
@Qualifier(“iocDao”)
private IIocDao xx;

因为Autowired 不能像Resource 那样带个参数指定一个name,就要用Qualifier来指定了。

而且还可以这么用

@Resource
@Qualifier(“iocDao”)
private IIocDao xx;

等同于

@Resource(name=”iocDao”)
private IIocDao xx;

记住一点:@Resource的作用相当于@Autowired,只不过@Autowired按byType自动注入,如果发现找到多个bean,则,又按照byName方式比对,如果还有多个,则报出异常 而@Resource默认按 byName自动注入罢了。其实spring注解,最常用的还是根据名称,根据类型啊,构造方法啊,用的非常少。所以在多个实现的时候我们定义好bean的名称就行,就不会错乱。

说了这么多,不知道对着几个注解是不是了解多一点了呢,貌似这些注解 没有根本上的区别,就看你习惯怎么用了。拿代码多跑几次,然后根据自己的想法改改,你就明白这几个注解的用处啦。

Spring JdbcTemplate批量操作数据库

 spring  Spring JdbcTemplate批量操作数据库已关闭评论
12月 062016
 

解决什么问题

提升数据操作性能,因为批量操作可以减少网络来回次数。

怎么做

方法1:使用jdbcTempalte的batchUpdate方法,第二个参数传入接口BatchPreparedStatementSetter接口,该接口需要实现两个方法,getBatchSize()用于获得该批数量,setValues(PreapredStatement ps, int i)用于设置每个PreparedStatement,以插入为例:

int batchInsert(final List<Stock> stockList)
    {
        logger.info(“batchInsert() begin, stockList.size=”+stockList.size());
        int[] updatedCountArray = getJdbcTemplate().batchUpdate(“insert into stock(id,code,name) value(?,?,?)”, new BatchPreparedStatementSetter() {
            
            public void setValues(PreparedStatement ps, int i) throws SQLException {
                // TODO Auto-generated method stub
                ps.setLong(1, stockList.get(i).getId());//要注意,下标从1开始
                ps.setString(2, stockList.get(i).getCode());
                ps.setString(3, stockList.get(i).getName());
            }
            
            public int getBatchSize() {
                
                return stockList.size();
            }
        });
        int sumInsertedCount = 0;
        for(int a: updatedCountArray)
        {
            sumInsertedCount+=a;
        }
        logger.info(“batchInsert() end, stockList.size=”+stockList.size()+”,success inserted “+sumInsertedCount+” records”);
        return sumInsertedCount;
    }

 

方法2:使用内置的SqlParamterSouce,从上面可以看出,代码还是写起来还是挺麻烦,赋值的时候很明显都是与Bean的属性名称有对应关系的,Spring因此提供了内置的方法来简化开发。因为需要足够的信息判断如何将对象的属性映射到sql中去,因此需要使用NamedJdbcTemplate。


int batchDelete(final List<Stock> stockList)
    {
        logger.info(“batchDelete() begin, codeList.size=”+stockList.size());
        SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(stockList.toArray());
        int[] updatedCountArray = getNamedParameterJdbcTemplate().batchUpdate(“delete from stock where code=:code”, batch);
        int sumInsertedCount = 0;
        for(int a: updatedCountArray)
        {
            sumInsertedCount+=a;
        }
        logger.info(“batchInsert() end, stockList.size=”+stockList.size()+”,success deleted “+sumInsertedCount+” records”);
        return sumInsertedCount;
    }

转自:http://www.cnblogs.com/lidabnu/p/5769732.html

servlet, spring, filter, listenr执行顺序

 java, spring  servlet, spring, filter, listenr执行顺序已关闭评论
11月 282016
 

web.xml 文件中一般包括 servlet, spring, filter, listenr的配置。那么他们是按照一个什么顺序加载呢?

加载顺序会影响对spring bean 的调用。

    比如filter 需要用到 bean ,但是加载顺序是 先加载filter 后加载spring,则filter中初始化操作中的bean为null;

首先可以肯定 加载顺序与他们在web.xml 文件中的先后顺序无关。

web.xml 中 listener 和 serverlet 的加载顺序为 先 listener 后serverlet

最终得出结果:先 listener >> filter >> servlet >>  spring 

 所以,如果过滤器中要使用到 bean,可以将spring 的加载 改成 Listener的方式

<listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

 搞定!

 

 

 

 关于他们的内部执行顺序,也需要注意,如下遇到的乱码问题

web.xml的filter执行顺序导致的乱码,切记!
发现引起bug的原因是web.xml的下面几行:
    <filter-mapping>
        <filter-name>SecurityFilter</filter-name>
        <url-pattern>*.do</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>CharacterEncoding</filter-name>
        <url-pattern>*.do</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>CharacterEncoding</filter-name>
        <url-pattern>*.jsp</url-pattern>
    </filter-mapping>
根据servlet2.3规范filter执行是按照web.xml配置的filter-mapping先后顺序进行执行,所以上面的配置会导致遇见*.do的url请求,先进行SecurityFilter的过滤器处理,这时候没有做编码处理,已经是乱码,到下面的filter处理时已经时乱码,再做编码处理已经没有用处。
修正方式,调整filter-mapping顺序,如下:
    <filter-mapping>
        <filter-name>CharacterEncoding</filter-name>
        <url-pattern>*.do</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>CharacterEncoding</filter-name>
        <url-pattern>*.jsp</url-pattern>
    </filter-mapping>
    <filter-mapping>
        <filter-name>SecurityFilter</filter-name>
        <url-pattern>*.do</url-pattern>
    </filter-mapping>

Spring 使用注解方式进行事务管理

 spring  Spring 使用注解方式进行事务管理已关闭评论
4月 282016
 

转自:http://www.cnblogs.com/younggun/archive/2013/07/16/3193800.html

使用步骤:

步骤一、在spring配置文件中引入<tx:>命名空间
<beans xmlns=”http://www.springframework.org/schema/beans”
 xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
 xmlns:tx=”http://www.springframework.org/schema/tx”
 xsi:schemaLocation=”http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
 http://www.springframework.org/schema/tx
 http://www.springframework.org/schema/tx/spring-tx-2.0.xsd”>

步骤二、具有@Transactional 注解的bean自动配置为声明式事务支持
 

复制代码
<!-- 事务管理器配置, Hibernate单数据源事务 --> <bean id="defaultTransactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- 使用annotation定义事务 --> <tx:annotation-driven transaction-manager="defaultTransactionManager" proxy-target-class="true" />
复制代码

 

步骤三、在接口或类的声明处 ,写一个@Transactional.
要是只在接口上写, 接口的实现类就会继承下来、接口的实现类的具体方法,可以覆盖类声明处的设置
@Transactional   //类级的注解、适用于类中所有的public的方法

事务的传播行为和隔离级别

大家在使用spring的注解式事务管理时,对事务的传播行为和隔离级别可能有点不知所措,下边就详细的介绍下以备方便查阅。

事物注解方式: @Transactional

当标于类前时, 标示类中所有方法都进行事物处理 , 例子:

@Transactional public class TestServiceBean implements TestService {} 

当类中某些方法不需要事物时:

复制代码
@Transactional public class TestServiceBean implements TestService { private TestDao dao; public void setDao(TestDao dao) { this.dao = dao;
    }   
    @Transactional(propagation = Propagation.NOT_SUPPORTED) public List<Object> getAll() { return null;
    }   
}
复制代码

事物传播行为介绍: 
@Transactional(propagation=Propagation.REQUIRED) 
如果有事务, 那么加入事务, 没有的话新建一个(默认情况下)
@Transactional(propagation=Propagation.NOT_SUPPORTED) 
容器不为这个方法开启事务
@Transactional(propagation=Propagation.REQUIRES_NEW) 
不管是否存在事务,都创建一个新的事务,原来的挂起,新的执行完毕,继续执行老的事务
@Transactional(propagation=Propagation.MANDATORY) 
必须在一个已有的事务中执行,否则抛出异常
@Transactional(propagation=Propagation.NEVER) 
必须在一个没有的事务中执行,否则抛出异常(与Propagation.MANDATORY相反)
@Transactional(propagation=Propagation.SUPPORTS) 
如果其他bean调用这个方法,在其他bean中声明事务,那就用事务.如果其他bean没有声明事务,那就不用事务.

事物超时设置:
@Transactional(timeout=30) //默认是30秒

事务隔离级别:
@Transactional(isolation = Isolation.READ_UNCOMMITTED)
读取未提交数据(会出现脏读, 不可重复读) 基本不使用
@Transactional(isolation = Isolation.READ_COMMITTED)
读取已提交数据(会出现不可重复读和幻读)
@Transactional(isolation = Isolation.REPEATABLE_READ)
可重复读(会出现幻读)
@Transactional(isolation = Isolation.SERIALIZABLE)
串行化

MYSQL: 默认为REPEATABLE_READ级别
SQLSERVER: 默认为READ_COMMITTED

脏读 : 一个事务读取到另一事务未提交的更新数据
不可重复读 : 在同一事务中, 多次读取同一数据返回的结果有所不同, 换句话说, 
后续读取可以读到另一事务已提交的更新数据. 相反, “可重复读”在同一事务中多次
读取数据时, 能够保证所读数据一样, 也就是后续读取不能读到另一事务已提交的更新数据
幻读 : 一个事务读到另一个事务已提交的insert数据

@Transactional注解中常用参数说明

参 数 名 称

功 能 描 述

readOnly

该属性用于设置当前事务是否为只读事务,设置为true表示只读,false则表示可读写,默认值为false。例如:@Transactional(readOnly=true)

rollbackFor

该属性用于设置需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,则进行事务回滚。例如:

指定单一异常类:@Transactional(rollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(rollbackFor={RuntimeException.class, Exception.class})

 续表)

参 数 名 称

功 能 描 述

rollbackForClassName

该属性用于设置需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,则进行事务回滚。例如:

指定单一异常类名称:@Transactional(rollbackForClassName=”RuntimeException”)

指定多个异常类名称:@Transactional(rollbackForClassName={“RuntimeException”,”Exception”})

noRollbackFor

该属性用于设置不需要进行回滚的异常类数组,当方法中抛出指定异常数组中的异常时,不进行事务回滚。例如:

指定单一异常类:@Transactional(noRollbackFor=RuntimeException.class)

指定多个异常类:@Transactional(noRollbackFor={RuntimeException.class, Exception.class})

noRollbackForClassName

该属性用于设置不需要进行回滚的异常类名称数组,当方法中抛出指定异常名称数组中的异常时,不进行事务回滚。例如:

指定单一异常类名称:@Transactional(noRollbackForClassName=”RuntimeException”)

指定多个异常类名称:

@Transactional(noRollbackForClassName={“RuntimeException”,”Exception”})

propagation

该属性用于设置事务的传播行为,具体取值可参考表6-7。

例如:@Transactional(propagation=Propagation.NOT_SUPPORTED,readOnly=true)

isolation

该属性用于设置底层数据库的事务隔离级别,事务隔离级别用于处理多事务并发的情况,通常使用数据库的默认隔离级别即可,基本不需要进行设置

timeout

该属性用于设置事务的超时秒数,默认值为-1表示永不超时

注意的几点:
1 @Transactional 只能被应用到public方法上, 对于其它非public的方法,如果标记了@Transactional也不会报错,但方法没有事务功能.
2用 spring 事务管理器,由spring来负责数据库的打开,提交,回滚.默认遇到运行期例外(throw new RuntimeException(“注释”);)会回滚,即遇到不受检查(unchecked)的例外时回滚;而遇到需要捕获的例外(throw new Exception(“注释”);)不会回滚,即遇到受检查的例外(就是非运行时抛出的异常,编译器会检查到的异常叫受检查例外或说受检查异常)时,需我们指定方式来让事务回滚 要想所有异常都回滚,要加上 @Transactional( rollbackFor={Exception.class,其它异常}) .如果让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)
如下:
@Transactional(rollbackFor=Exception.class) //指定回滚,遇到异常Exception时回滚
public void methodName() {
throw new Exception(“注释”);
}
@Transactional(noRollbackFor=Exception.class)//指定不回滚,遇到运行期例外(throw new RuntimeException(“注释”);)会回滚
public ItimDaoImpl getItemDaoImpl() {
throw new RuntimeException(“注释”);
}

3、@Transactional 注解应该只被应用到 public 可见度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不会报错, 但是这个被注解的方法将不会展示已配置的事务设置。


4、@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。然而,请注意仅仅 @Transactional 注解的出现不足于开启事务行为,它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 <tx:annotation-driven/>元素的出现 开启 了事务行为。


5、Spring团队的建议是你在具体的类(或类的方法)上使用 @Transactional 注解,而不要使用在类所要实现的任何接口上。你当然可以在接口上使用 @Transactional 注解,但是这将只能当你设置了基于接口的代理时它才生效。因为注解是 不能继承 的,这就意味着如果你正在使用基于类的代理时,那么事务的设置将不能被基于类的代理所识别,而且对象也将不会被事务代理所包装(将被确认为严重的)。因 此,请接受Spring团队的建议并且在具体的类上使用 @Transactional 注解。

MySQL事务学习(分布式事务) 及spring中使用

 java  MySQL事务学习(分布式事务) 及spring中使用已关闭评论
8月 042015
 

分布式事务

Innodb存储引擎支持XA事务,通过XA事务可以支持分布式事务的实现。分布式事务指的是允许多个独立的事务资源(transac         tional resources)参与一个全局的事务中。事务资源通常是关系型数据库系统,也可以是其它类型的资源。

 

全局事务要求在其中所有参与的事务要么全部提交,要么全部回滚,这对于事务原有的ACID要求又有了提高。另外,在使用分布式事务时候,InnoDB存储引擎的事务隔离级别必须设置成serialiable。

 

XA事务允许不同数据库之间的分布式事务,如:一台服务器是mysql数据库,一台是oracle的,又有可能还有一台是sqlserver的,只要参与全局事务中的每个节点都支持XA事务。分布式事务可能在银行系统的转帐中比较常见,如一个用户需要从上海转1000元到北京的一个用户账号上面:

# bank ofshanghai:

Updateuser_account set money=money – 10000 where user=’xiaozhang’;

# bank ofBeijing:

Updateuser_account set money= money + 10000 where user=’xiaoli’;

像这种情况一定需要分布式的事务,要不都提交,要么都回滚。在任何一个节点出问题都会造成严重的结果:1 xiaozhang的帐号被扣款,但是xiaoli没有收到钱;2 xiaozhang的帐号没有被扣款,但是xiaoli收到钱了。

 

分布式事务是由一个或者多个Resource Managerd,一个事务管理器Transaction Manager以及一个应用程序 Application Program组成。

资源管理器:提供访问事务资源的方法,通常一个数据库就是一个资源管理器。

事务管理器:协调参与全局事务中的各个事务。需要和参与全局事务中的资源管理器进行通信。

应用程序:定义事务的边界,指定全局事务中的操作。

在mysql中的分布式事务中,资源管理器就是mysql数据库,事务管理器为连接到mysql服务器的客户端。如下图所示:

 

分布式事务使用两段式提交(two-phase commit)的方式。在第一个阶段,所有参与全局事务的节点都开始准备,告诉事务管理器它们准备好提交了。第二个阶段,事务管理器告诉资源管理器执行rollback或者commit,如果任何一个节点显示不能commit,那么所有的节点就得全部rollback。

当前的java的jta java transaction API可以很好的支持mysql的分布式事务,可以仔细参考jta手册。下面的例子显示了如何使用jta支持调用mysql分布式事务。

参数innodb_support_xa可以查看是否启用了XA事务支持(默认为on开启状态):

  1. mysql> show variables like‘innodb_support%’;  
  2. +——————-+——-+  
  3. | Variable_name     | Value |  
  4. +——————-+——-+  
  5. | innodb_support_xa | ON    |  
  6. +——————-+——-+  
  7. 1 row in set (0.00 sec)  
  8.    
  9. mysql>  

[注意] 对于XA事务的支持,是在mysql体系结构的存储引擎层。因此即使不参与外部的XA事务,mysql事务内部不同存储引擎也会使用xa事务。假设我们用start  transaction开启了一个本地的事务,往NDB Cluster存储引擎的表t1插入一条记录,往innodb存储引擎的表t2插入一条记录,然后commit,在mysql内部也是通过xa事务来进行协调的,这样才可以保证2张表的原子性。

转自:http://blog.csdn.net/mchdba/article/details/13076803

spring分布式事务实现

 分布式事务是指操作多个数据库之间的事务,spring的org.springframework.transaction.jta.JtaTransactionManager,提供了分布式事务支持。如果使用WAS的JTA支持,把它的属性改为WebSphere对应的TransactionManager。 
    在tomcat下,是没有分布式事务的,不过可以借助于第三方软件jotm(Java Open Transaction Manager )和AtomikosTransactionsEssentials实现,在spring中分布式事务是通过jta(jotm,atomikos)来进行实现。 
1、http://jotm.objectweb.org/ 
2、http://www.atomikos.com/Main/TransactionsEssentials 
一、使用JOTM例子 
(1)、Dao及实现 

Java代码  收藏代码

  1. public interface GenericDao {  
  2.   
  3.     public int save(String ds, String sql, Object[] obj) throws Exception;  
  4.       
  5.     public int findRowCount(String ds, String sql);  
  6.       
  7. }  

Java代码  收藏代码

  1. public class GenericDaoImpl implements GenericDao{  
  2.   
  3.     private  JdbcTemplate jdbcTemplateA;  
  4.     private  JdbcTemplate jdbcTemplateB;  
  5.   
  6.     public void setJdbcTemplateA(JdbcTemplate jdbcTemplate) {  
  7.         this.jdbcTemplateA = jdbcTemplate;  
  8.     }  
  9.   
  10.     public void setJdbcTemplateB(JdbcTemplate jdbcTemplate) {  
  11.         this.jdbcTemplateB = jdbcTemplate;  
  12.     }  
  13.       
  14.     public int save(String ds, String sql, Object[] obj) throws Exception{  
  15.         if(null == ds || “”.equals(ds)) return –1;  
  16.         try{  
  17.             if(ds.equals(“A”)){  
  18.                 return this.jdbcTemplateA.update(sql, obj);  
  19.             }else{  
  20.                 return this.jdbcTemplateB.update(sql, obj);  
  21.             }  
  22.         }catch(Exception e){  
  23.             e.printStackTrace();  
  24.             throw new Exception(“执行” + ds + “数据库时失败!”);  
  25.         }  
  26.     }  
  27.   
  28.     public int findRowCount(String ds, String sql) {  
  29.         if(null == ds || “”.equals(ds)) return –1;  
  30.           
  31.         if(ds.equals(“A”)){  
  32.             return this.jdbcTemplateA.queryForInt(sql);  
  33.         }else{  
  34.             return this.jdbcTemplateB.queryForInt(sql);  
  35.         }  
  36.     }  
  37.   
  38. }  

(2)、Service及实现 

Java代码  收藏代码

  1. public interface UserService {  
  2.       
  3.     public void saveUser() throws Exception;  
  4.       
  5. }  

Java代码  收藏代码

  1. public class UserServiceImpl implements UserService{  
  2.   
  3.     private GenericDao genericDao;  
  4.       
  5.     public void setGenericDao(GenericDao genericDao) {  
  6.         this.genericDao = genericDao;  
  7.     }  
  8.   
  9.     public void saveUser() throws Exception {  
  10.         String userName = “user_” + Math.round(Math.random()*10000);  
  11.         System.out.println(userName);  
  12.           
  13.         StringBuilder sql = new StringBuilder();  
  14.         sql.append(” insert into t_user(username, gender) values(?,?); “);  
  15.         Object[] objs = new Object[]{userName,“1”};  
  16.           
  17.         genericDao.save(“A”, sql.toString(), objs);  
  18.           
  19.         sql.delete(0, sql.length());  
  20.         sql.append(” insert into t_user(name, sex) values(?,?); “);  
  21.         objs = new Object[]{userName,“男的”};//值超出范围  
  22.         genericDao.save(“B”, sql.toString(), objs);  
  23.     }  
  24.   
  25. }  

(3)、applicationContext-jotm.xml 

Xml代码  收藏代码

  1. <?xml version=“1.0” encoding=“UTF-8”?>  
  2.   
  3. <beans xmlns=“http://www.springframework.org/schema/beans”   
  4.     xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance”   
  5.     xmlns:context=“http://www.springframework.org/schema/context”   
  6.     xmlns:aop=“http://www.springframework.org/schema/aop”   
  7.     xmlns:tx=“http://www.springframework.org/schema/tx”   
  8.     xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   
  9.     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd   
  10.     http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd   
  11.     http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd”>  
  12.   
  13.     <description>springJTA</description>  
  14.   
  15.     <!–指定Spring配置中用到的属性文件–>   
  16.     <bean id=“propertyConfig”   
  17.             class=“org.springframework.beans.factory.config.PropertyPlaceholderConfigurer”>   
  18.         <property name=“locations”>   
  19.             <list>   
  20.                 <value>classpath:jdbc.properties</value>   
  21.             </list>   
  22.         </property>   
  23.     </bean>   
  24.       
  25.     <!– JOTM实例 –>  
  26.     <bean id=“jotm” class=“org.springframework.transaction.jta.JotmFactoryBean”>  
  27.           <property name=“defaultTimeout” value=“500000”/>  
  28.     </bean>  
  29.   
  30.     <!– JTA事务管理器 –>  
  31.     <bean id=“jtaTransactionManager” class=“org.springframework.transaction.jta.JtaTransactionManager”>     
  32.         <property name=“userTransaction” ref=“jotm” />     
  33.     </bean>  
  34.   
  35.     <!– 数据源A –>   
  36.     <bean id=“dataSourceA” class=“org.enhydra.jdbc.pool.StandardXAPoolDataSource” destroy-method=“shutdown”>   
  37.        <property name=“dataSource”>   
  38.            <bean class=“org.enhydra.jdbc.standard.StandardXADataSource” destroy-method=“shutdown”>   
  39.                <property name=“transactionManager” ref=“jotm”/>   
  40.                <property name=“driverName” value=“${jdbc.driver}”/>   
  41.                <property name=“url” value=“${jdbc.url}”/>   
  42.            </bean>   
  43.        </property>   
  44.        <property name=“user” value=“${jdbc.username}”/>   
  45.        <property name=“password” value=“${jdbc.password}”/>   
  46.     </bean>   
  47.   
  48.     <!– 数据源B –>   
  49.     <bean id=“dataSourceB” class=“org.enhydra.jdbc.pool.StandardXAPoolDataSource” destroy-method=“shutdown”>   
  50.        <property name=“dataSource”>   
  51.            <bean class=“org.enhydra.jdbc.standard.StandardXADataSource” destroy-method=“shutdown”>   
  52.                <property name=“transactionManager” ref=“jotm”/>   
  53.                <property name=“driverName” value=“${jdbc2.driver}”/>   
  54.                <property name=“url” value=“${jdbc2.url}”/>   
  55.            </bean>   
  56.        </property>   
  57.        <property name=“user” value=“${jdbc2.username}”/>   
  58.        <property name=“password” value=“${jdbc2.password}”/>   
  59.     </bean>   
  60.   
  61.     <bean id = “jdbcTemplateA”   
  62.          class = “org.springframework.jdbc.core.JdbcTemplate”>   
  63.          <property name = “dataSource” ref=“dataSourceA”/>   
  64.     </bean>  
  65.       
  66.     <bean id = “jdbcTemplateB”   
  67.          class = “org.springframework.jdbc.core.JdbcTemplate”>   
  68.          <property name = “dataSource” ref=“dataSourceB”/>   
  69.     </bean>      
  70.   
  71.     <!– 事务切面配置 –>   
  72.     <aop:config>   
  73.         <aop:pointcut id=“pointCut”  
  74.                 expression=“execution(* com.logcd.service..*.*(..))”/><!– 包及其子包下的所有方法 –>  
  75.         <aop:advisor pointcut-ref=“pointCut” advice-ref=“txAdvice”/>   
  76.           
  77.         <aop:advisor pointcut=“execution(* *..common.service..*.*(..))” advice-ref=“txAdvice”/>  
  78.     </aop:config>   
  79.   
  80.     <!– 通知配置 –>   
  81.     <tx:advice id=“txAdvice” transaction-manager=“jtaTransactionManager”>   
  82.        <tx:attributes>   
  83.           <tx:method name=“delete*” rollback-for=“Exception”/>   
  84.           <tx:method name=“save*” rollback-for=“Exception”/>   
  85.           <tx:method name=“update*” rollback-for=“Exception”/>   
  86.           <tx:method name=“find*” read-only=“true” rollback-for=“Exception”/>   
  87.        </tx:attributes>   
  88.     </tx:advice>   
  89.   
  90.     <bean id=“genericDao”   
  91.             class=“com.logcd.dao.impl.GenericDaoImpl” autowire=“byName”>  
  92.     </bean>  
  93.   
  94.     <bean id=“userService”   
  95.             class=“com.logcd.service.impl.UserServiceImpl” autowire=“byName”>  
  96.     </bean>  
  97.   
  98. </beans>  

(4)、测试 

Java代码  收藏代码

  1. public class TestUserService{  
  2.   
  3.     private static UserService userService;  
  4.       
  5.     @BeforeClass  
  6.     public static void init(){  
  7.         ApplicationContext app = new ClassPathXmlApplicationContext(“applicationContext-jotm.xml”);  
  8.         userService = (UserService)app.getBean(“userService”);  
  9.     }  
  10.       
  11.     @Test  
  12.     public void save(){  
  13.         System.out.println(“begin…”);  
  14.         try{  
  15.             userService.saveUser();  
  16.         }catch(Exception e){  
  17.             System.out.println(e.getMessage());  
  18.         }  
  19.         System.out.println(“finish…”);  
  20.     }  
  21.       
  22. }  

二、关于使用atomikos实现 
(1)、数据源配置 

Xml代码  收藏代码

  1. <bean id=“dataSourceA” class=“com.atomikos.jdbc.SimpleDataSourceBean” init-method=“init” destroy-method=“close”>  
  2.     <property name=“uniqueResourceName”>  
  3.         <value>${datasource.uniqueResourceName}</value>  
  4.     </property>  
  5.     <property name=“xaDataSourceClassName”>   
  6.         <value>${database.driver_class}</value>   
  7.     </property>   
  8.     <property name=“xaDataSourceProperties”>  
  9.         <value>URL=${database.url};user=${database.username};password=${database.password}</value>   
  10.     </property>   
  11.     <property name=“exclusiveConnectionMode”>   
  12.         <value>${connection.exclusive.mode}</value>   
  13.     </property>  
  14.     <property name=“connectionPoolSize”>   
  15.         <value>${connection.pool.size}</value>  
  16.     </property>  
  17.     <property name=“connectionTimeout”>  
  18.         <value>${connection.timeout}</value>  
  19.     </property>  
  20.     <property name=“validatingQuery”>   
  21.         <value>SELECT 1</value>   
  22.     </property>   
  23. </bean>  

(2)、事务配置 

Xml代码  收藏代码

  1. <bean id=“atomikosTransactionManager” class=“com.atomikos.icatch.jta.UserTransactionManager”   
  2.     init-method=“init” destroy-method=“close”>   
  3.     <property name=“forceShutdown” value=“true”/>   
  4. </bean>   
  5.   
  6. <bean id=“atomikosUserTransaction” class=“com.atomikos.icatch.jta.UserTransactionImp”>   
  7.     <property name=“transactionTimeout” value=“${transaction.timeout}”/>   
  8. </bean>  
  9.   
  10. <!– JTA事务管理器 –>   
  11. <bean id=“springTransactionManager” class=“org.springframework.transaction.jta.JtaTransactionManager”>   
  12.     <property name=“transactionManager” ref=“atomikosTransactionManager”/>   
  13.     <property name=“userTransaction” ref=“atomikosUserTransaction”/>   
  14. </bean>  
  15.   
  16. <!– 事务切面配置 –>   
  17. <aop:config>   
  18.     <aop:pointcut id=“serviceOperation”  expression=“execution(* *..service*..*(..))”/>   
  19.     <aop:advisor pointcut-ref=“serviceOperation” advice-ref=“txAdvice”/>   
  20. </aop:config>  
  21.   
  22. <!– 通知配置 –>  
  23. <tx:advice id=“txAdvice” transaction-manager=“springTransactionManager”>   
  24.     <tx:attributes>  
  25.         <tx:method name=“*” rollback-for=“Exception”/>   
  26.     </tx:attributes>   
  27. </tx:advice>   

转自:http://log-cd.iteye.com/blog/807607

rabbitmq在spring中配置

 spring  rabbitmq在spring中配置已关闭评论
3月 132015
 

rabbitmq在spring中配置,记录下备用

本文侧重介绍如何将rabbitmq整合到spring项目中

maven 依赖包配置如下: 

<dependencies>
    <dependency>
        <groupId>org.springframework.amqp</groupId>
        <artifactId>spring-rabbit</artifactId>
        <version>1.2.0.RELEASE</version>
    </dependency>
</dependencies>

1.首先是生产者配置

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?xmlversion=”1.0″encoding=”UTF-8″?>
<beansxmlns=”http://www.springframework.org/schema/beans”
       xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
       xmlns:context=”http://www.springframework.org/schema/context”
       xmlns:rabbit=”http://www.springframework.org/schema/rabbit”
       xsi:schemaLocation=”
            http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/rabbit
                http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd”>
 
     
   <!– 连接服务配置  –>
   <rabbit:connection-factoryid=”connectionFactory”host=”localhost”username=”guest”
        password=”guest”port=”5672″ />
         
   <rabbit:adminconnection-factory=”connectionFactory”/>
    
   <!– queue 队列声明–>
   <rabbit:queueid=”queue_one”durable=”true”auto-delete=”false”exclusive=”false”name=”queue_one”/>
    
    
   <!– exchange queue binging key 绑定 –>
    <rabbit:direct-exchangename=”my-mq-exchange”durable=”true”auto-delete=”false”id=”my-mq-exchange<span></span>”>
        <rabbit:bindings>
            <rabbit:bindingqueue=”queue_one”key=”queue_one_key”/>
        </rabbit:bindings>
    </rabbit:direct-exchange>
     
    <– spring amqp默认的是jackson 的一个插件,目的将生产者生产的数据转换为json存入消息队列,由于fastjson的速度快于jackson,这里替换为fastjson的一个实现 –>
    <beanid=”jsonMessageConverter” class=”mq.convert.FastJsonMessageConverter”></bean>
     
    <– spring template声明–>
    <rabbit:templateexchange=”my-mq-exchange”id=”amqpTemplate” connection-factory=”connectionFactory” message-converter=”jsonMessageConverter”/>
</beans>

2.fastjson messageconver插件实现

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
importorg.apache.commons.logging.Log;
importorg.apache.commons.logging.LogFactory;
importorg.springframework.amqp.core.Message;
importorg.springframework.amqp.core.MessageProperties;
importorg.springframework.amqp.support.converter.AbstractMessageConverter;
importorg.springframework.amqp.support.converter.MessageConversionException;
 
importfe.json.FastJson;
 
publicclassFastJsonMessageConverter extendsAbstractMessageConverter {
    privatestaticLog log = LogFactory.getLog(FastJsonMessageConverter.class);
 
    publicstaticfinalString DEFAULT_CHARSET =”UTF-8″;
 
    privatevolatileString defaultCharset = DEFAULT_CHARSET;
     
    publicFastJsonMessageConverter() {
        super();
        //init();
    }
     
    publicvoidsetDefaultCharset(String defaultCharset) {
        this.defaultCharset = (defaultCharset !=null) ? defaultCharset
                : DEFAULT_CHARSET;
    }
     
    publicObject fromMessage(Message message)
            throwsMessageConversionException {
        returnnull;
    }
     
    public<T> T fromMessage(Message message,T t) {
        String json =””;
        try{
            json =newString(message.getBody(),defaultCharset);
        }catch(UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return(T) FastJson.fromJson(json, t.getClass());
    }  
     
 
    protectedMessage createMessage(Object objectToConvert,
            MessageProperties messageProperties)
            throwsMessageConversionException {
        byte[] bytes =null;
        try{
            String jsonString = FastJson.toJson(objectToConvert);
            bytes = jsonString.getBytes(this.defaultCharset);
        }catch(UnsupportedEncodingException e) {
            thrownewMessageConversionException(
                    “Failed to convert Message content”, e);
        }
        messageProperties.setContentType(MessageProperties.CONTENT_TYPE_JSON);
        messageProperties.setContentEncoding(this.defaultCharset);
        if(bytes !=null) {
            messageProperties.setContentLength(bytes.length);
        }
        returnnewMessage(bytes, messageProperties);
 
    }
}

3.生产者端调用

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
importjava.util.List;
 
importorg.springframework.amqp.core.AmqpTemplate;
 
 
publicclassMyMqGatway {
     
    @Autowired
    privateAmqpTemplate amqpTemplate;
     
    publicvoidsendDataToCrQueue(Object obj) {
        amqpTemplate.convertAndSend(“queue_one_key”, obj);
    }  
}

4.消费者端配置(与生产者端大同小异)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?xmlversion=”1.0″encoding=”UTF-8″?>
<beansxmlns=”http://www.springframework.org/schema/beans”
       xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
       xmlns:context=”http://www.springframework.org/schema/context”
       xmlns:rabbit=”http://www.springframework.org/schema/rabbit”
       xsi:schemaLocation=”
            http://www.springframework.org/schema/beans
                http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
                http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/rabbit
                http://www.springframework.org/schema/rabbit/spring-rabbit-1.0.xsd”>
 
     
   <!– 连接服务配置  –>
   <rabbit:connection-factoryid=”connectionFactory”host=”localhost”username=”guest”
        password=”guest”port=”5672″ />
         
   <rabbit:adminconnection-factory=”connectionFactory”/>
    
   <!– queue 队列声明–>
   <rabbit:queueid=”queue_one”durable=”true”auto-delete=”false”exclusive=”false”name=”queue_one”/>
    
    
   <!– exchange queue binging key 绑定 –>
    <rabbit:direct-exchangename=”my-mq-exchange”durable=”true”auto-delete=”false”id=”my-mq-exchange”>
        <rabbit:bindings>
            <rabbit:bindingqueue=”queue_one”key=”queue_one_key”/>
        </rabbit:bindings>
    </rabbit:direct-exchange>
 
     
      
    <!– queue litener  观察 监听模式 当有消息到达时会通知监听在对应的队列上的监听对象–>
    <rabbit:listener-containerconnection-factory=”connectionFactory”acknowledge=”auto”task-executor=”taskExecutor”>
        <rabbit:listenerqueues=”queue_one”ref=”queueOneLitener”/>
    </rabbit:listener-container>
</beans>

5.消费者端调用

?
1
2
3
4
5
6
7
8
9
importorg.springframework.amqp.core.Message;
importorg.springframework.amqp.core.MessageListener;
 
publicclassQueueOneLitenerimplements MessageListener{
    @Override
    publicvoidonMessage(Message message) {
        System.out.println(” data :”+ message.getBody());
    }
}

6.由于消费端当队列有数据到达时,对应监听的对象就会被通知到,无法做到批量获取,批量入库,因此可以在消费端缓存一个临时队列,将mq取出来的数据存入本地队列,后台线程定时批量处理即可

转自:http://my.oschina.net/never/blog/140368

Spring Quartz *.QRTZ_LOCKS' doesn't exist 异常解决方法

 未分类  Spring Quartz *.QRTZ_LOCKS' doesn't exist 异常解决方法已关闭评论
2月 132014
 

在使用 Spring Quartz框架做计划任务时,遇到错误提示,如下:

 

ERROR [org.springframework.web.context.ContextLoader] – Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘org.springframework.scheduling.quartz.SchedulerFactoryBean#0’ defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is org.quartz.SchedulerConfigException: Failure occured during job recovery. [See nested exception: org.quartz.impl.jdbcjobstore.LockException: Failure obtaining db row lock: Table ‘zp60v1_db.QRTZ_LOCKS’ doesn’t exist [See nested exception: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Table ‘zp60v1_db.QRTZ_LOCKS’ doesn’t exist]]
 at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean

….

 

开发环境:
JDK 1.6
GWT 2.0
SmartGwt pro 2.0
Hibernate 3.2
Spring 2.5

 

applicationContext.xml:

[xhtml] view plaincopy

  1. <beans default-autowire=”autodetect”> <!–autowire is the cause of exception–>  
  2.                <bean id=”dataSource” class=”org.apache.commons.dbcp.BasicDataSource”>  
  3.                       ……  
  4.                </bean>  
  5.                <bean id=”sessionFactory” class=”org.springframework.orm.hibernate3.LocalSessionFactoryBean”>  
  6.                      ……  
  7.                </bean>  
  8.                     …….  
  9.               <bean id=”cronReportTrigger” class=”org.springframework.scheduling.quartz.CronTriggerBean”>  
  10.                     ……  
  11.               </bean>  
  12.               <bean id=”schedulerFactoryBean” class=”org.springframework.scheduling.quartz.SchedulerFactoryBean”>  
  13.                         <property name=”triggers”>  
  14.                               <list>  
  15.                                       <ref bean=”cronReportTrigger”/>  
  16.                               </list>  
  17.                         </property>  
  18.               </bean>  
  19.         </beans>  

 

为了定时执行一项任务,设置了Quartz , 但是运行后异常” Failure obtaining db row lock: Table ‘hibernate.qrtz_locks’ doesn’t exist“,相信你肯定会感到困惑,甚至也许会奇怪为什么 SchedulerFactoryBean 和数据持久层有关。

 

原因:

事实上,这个异常是由于 Spring 的 autowire 属性引起的,SchedulerFactoryBean  类含有方法 : setDataSource. 因为autowire 属性使用了 autodetect , 并且也设置了 datasource 在项目中, spring 容器就自动将 dataSource 注入到SchedulerFactoryBean, 而SchedulerFactoryBean将从 dataSource 中查找计划任务。 但 dataSource 中并没有任务,因此抛出了异常。

幸运的是,当你知道了根本原因,就知道如何避免了。

 

解决方法:

不论 spring 的 default-autowire 设置为”autodetect ” 还是 “byName” ,都会出现 *.QRTZ_LOCKS’ doesn’t exist

方法一: 不使用 default-autowire 属性;

方法二: 在不改变 spring default-autowire  属性的前提下, 给 SchedulerFactoryBean  设置 autowire=”no”。

 

[xhtml] view plaincopy

  1. <bean class=”org.springframework.scheduling.quartz.SchedulerFactoryBean” autowire=”no”>  
  2.         <property name=”triggers”>  
  3.             <list>  
  4.                 <ref bean=”simpleTriggerBean” />  
  5.             </list>  
  6.         </property>  

转自:http://blog.csdn.net/usedtolove/article/details/5265701

Spring集成Quartz定时任务框架及Cron表达式详解

 java, spring  Spring集成Quartz定时任务框架及Cron表达式详解已关闭评论
2月 122014
 

在JavaEE系统中,我们会经常用到定时任务,比如每天凌晨生成前天报表,每一小时生成汇总数据等等。
我们可以使用java.util.Timer结合java.util.TimerTask来完成这项工作,但时调度控制非常不方便,并且我们需要大量的代码。
使用Quartz框架无疑是非常好的选择,并且与Spring可以非常方便的集成,下面介绍它们集成方法和Cron表达式的详细介绍。

一、增加所依赖的JAR包
1、增加Spring的Maven依赖

	
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>3.0.5.RELEASE</version> </dependency>

2、增加Quartz的Maven依赖

	
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>1.8.4</version> </dependency>

二、增加定时业务逻辑类

复制代码
	
public class ExpireJobTask { /** Logger */ private static final Logger logger = LoggerFactory.getLogger(ExpireJobTask.class); /** * 业务逻辑处理 */ public void doBiz() { // 执行业务逻辑 // ........ } }
复制代码

ExpireJobTask业务逻辑类与一般普通的类没有任务区别,它定义的doBiz方法即为调度业务方法。

三、增加Spring配置
1、增加一个线程池

复制代码
	
<!-- 线程执行器配置,用于任务注册 --> <bean id="executor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor"> <property name="corePoolSize" value="10" /> <property name="maxPoolSize" value="100" /> <property name="queueCapacity" value="500" /> </bean>
复制代码

2、定义业务逻辑处理类

	
<!-- 业务对象 --> <bean id="bizObject" class="com.aboy.potak.common.toolkit.scheduling.ExpireJobTask" />

3、增加调度业务逻辑

复制代码
	
<!-- 调度业务 --> <bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="bizObject" /> <property name="targetMethod" value="doBiz" /> </bean>
复制代码

上面的配置中,我们以bizObject.doBiz方法为将要调度的业务执行逻辑。
4、增加调度触发器

	
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail" ref="jobDetail" /> <property name="cronExpression" value="10 0/1 * * * ?" /> </bean>

Cron表达式“10 */1 * * * ?”意为:从10秒开始,每1分钟执行一次。

	
<bean id="taskTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> <property name="jobDetail" ref="jobDetail" /> <property name="startDelay" value="10000" /> <property name="repeatInterval" value="60000" /> </bean>

该调度表示,延迟10秒启动,然后每隔1分钟执行一次。
5、增加调度

复制代码
	
<!-- 设置调度 --> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="cronTrigger" /> </list> </property> <property name="taskExecutor" ref="executor" /> </bean>
复制代码

triggers属性中,我们可以增加多个触发器。

到此,Spring已经与Quartz完美的结合了,我们接下来的工作就是启动系统,开始调度了。

四、Cron表达式的详细用法
字段 允许值 允许的特殊字符 
秒 0-59 , – * / 
分 0-59 , – * / 
小时 0-23 , – * / 
日期 1-31 , – * ? / L W C 
月份 1-12 或者 JAN-DEC , – * / 
星期 1-7 或者 SUN-SAT , – * ? / L C # 
年(可选) 留空, 1970-2099 , – * /

例子:
0/5 * * * * ? : 每5秒执行一次

“*”字符被用来指定所有的值。如:”*”在分钟的字段域里表示“每分钟”。 
“?”字符只在日期域和星期域中使用。它被用来指定“非明确的值”。当你需要通过在这两个域中的一个来指定一些东西的时候,它是有用的。看下面的例子你就会明白。 
月份中的日期和星期中的日期这两个元素时互斥的一起应该通过设置一个问号来表明不想设置那个字段。

“-”字符被用来指定一个范围。如:“10-12”在小时域意味着“10点、11点、12点”。

“,”字符被用来指定另外的值。如:“MON,WED,FRI”在星期域里表示”星期一、星期三、星期五”。

“/”字符用于指定增量。如:“0/15”在秒域意思是每分钟的0,15,30和45秒。“5/15”在分钟域表示每小时的5,20,35和50。符号“*”在“/”前面(如:*/10)等价于0在“/”前面(如:0/10)。记住一条本质:表达式的每个数值域都是一个有最大值和最小值的集合,如:秒域和分钟域的集合是0-59,日期域是1-31,月份域是1-12。字符“/”可以帮助你在每个字符域中取相应的数值。如:“7/6”在月份域的时候只有当7月的时候才会触发,并不是表示每个6月。

L是‘last’的省略写法可以表示day-of-month和day-of-week域,但在两个字段中的意思不同,例如day-of-month域中表示一个月的最后一天。如果在day-of-week域表示‘7’或者‘SAT’,如果在day-of-week域中前面加上数字,它表示一个月的最后几天,例如‘6L’就表示一个月的最后一个星期五。

字符“W”只允许日期域出现。这个字符用于指定日期的最近工作日。例如:如果你在日期域中写 “15W”,表示:这个月15号最近的工作日。所以,如果15号是周六,则任务会在14号触发。如果15好是周日,则任务会在周一也就是16号触发。如果是在日期域填写“1W”即使1号是周六,那么任务也只会在下周一,也就是3号触发,“W”字符指定的最近工作日是不能够跨月份的。字符“W”只能配合一个单独的数值使用,不能够是一个数字段,如:1-15W是错误的。

“L”和“W”可以在日期域中联合使用,LW表示这个月最后一周的工作日。

字符“#”只允许在星期域中出现。这个字符用于指定本月的某某天。例如:“6#3”表示本月第三周的星期五(6表示星期五,3表示第三周)。“2#1”表示本月第一周的星期一。“4#5”表示第五周的星期三。

字符“C”允许在日期域和星期域出现。这个字符依靠一个指定的“日历”。也就是说这个表达式的值依赖于相关的“日历”的计算结果,如果没有“日历”关联,则等价于所有包含的“日历”。如:日期域是“5C”表示关联“日历”中第一天,或者这个月开始的第一天的后5天。星期域是“1C”表示关联“日历”中第一天,或者星期的第一天的后1天,也就是周日的后一天(周一)。

五、表达式举例
“0 0 12 * * ?” 每天中午12点触发
“0 15 10 ? * *” 每天上午10:15触发
“0 15 10 * * ?” 每天上午10:15触发
“0 15 10 * * ? *” 每天上午10:15触发
“0 15 10 * * ? 2005” 2005年的每天上午10:15触发
“0 * 14 * * ?” 在每天下午2点到下午2:59期间的每1分钟触发
“0 0/5 14 * * ?” 在每天下午2点到下午2:55期间的每5分钟触发
“0 0/5 14,18 * * ?” 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
“0 0-5 14 * * ?” 在每天下午2点到下午2:05期间的每1分钟触发
“0 10,44 14 ? 3 WED” 每年三月的星期三的下午2:10和2:44触发
“0 15 10 ? * MON-FRI” 周一至周五的上午10:15触发
“0 15 10 15 * ?” 每月15日上午10:15触发
“0 15 10 L * ?” 每月最后一日的上午10:15触发
“0 15 10 ? * 6L” 每月的最后一个星期五上午10:15触发 
“0 15 10 ? * 6L 2002-2005” 2002年至2005年的每月的最后一个星期五上午10:15触发
“0 15 10 ? * 6#3” 每月的第三个星期五上午10:15触发

转自:http://www.cnblogs.com/obullxl/archive/2011/07/10/spring-quartz-cron-integration.html

Spring ApplicationContext.xml配置的12个技巧和Bean属性说明(转)

 java, spring  Spring ApplicationContext.xml配置的12个技巧和Bean属性说明(转)已关闭评论
2月 282013
 

转自:http://blog.csdn.net/mqboss/article/details/5868113

Spring ApplicationContext.xml配置的12个技巧

 

Spring是一个强有力的java程序框架,其被广泛应用于java的程序中。它用POJO提供了企业级服务。 Spring利用依赖注入可以获得简单而有效的测试能力。Spring beans,依赖关系,以及服务所需要的bean都将在配置文件中予以描述,配置文件一般采用XML格式。然而XML配置文件冗长而不易使用,在你进行一 个使用了大量bean的大项目中它将变得难以阅读和控制。

 

在这篇文章中我将给你展示12种的有关Spring XML配置文件的最佳技巧。它们中的一些具有更多的实际意义,而不仅是最好的技巧。请注意另外一些因素,例如域模型的设计,会影响到XML配置,但是这篇文章更关注于XML配置的可读性和可操控性。

 

1.避免使用自动装配

Spring 可以通过bean类的自省来实现自动装配依赖,这样的话你就不必明确地描述bean的属性或者构造函数的参数。根据属性名称活匹配类型,bean属性可以 自动进行装配。而构造函数可以根据匹配类型自动装配。你甚至可以设置自动装配进行自动侦测,这样Spring替你就会选择一个合适的机制。请看下面的例 子:

 

 

Spring 可以通过bean类的自省来实现自动装配依赖,这样的话你就不必明确地描述bean的属性或者构造函数的参数。根据属性名称活匹配类型,bean属性可以 自动进行装配。而构造函数可以根据匹配类型自动装配。你甚至可以设置自动装配进行自动侦测,这样Spring替你就会选择一个合适的机制。请看下面的例 子:

 

<bean id=”orderService”

class=”com.lizjason.spring.OrderService”

autowire=”byName”/>

 

OrderService 类的属性名被用来和容器中的一个bean实例进行匹配。自动装配会默默的保存一些类型信息并降低混乱。然而,由于它会牺牲掉这种配置的直观性和可维护性, 你在实际的项目中将不会用到它。许多指南和陈述材料都把它吹捧为Spring的一个非常cool的特性,而没有提到它的这个缺点。依我之见,就像 Spring的对象池一样,它更多了一些商业味道。它看起来好像可以使XML配置文件更精简一些,但实际上却增加其复杂性,尤其是在你的较大规模的工程中 已经定义了很多bean的时候更是如此。Spring允许你混合使用自动和手动装配,但是这种矛盾会使XML配置更加的令人费解。

 

2.使用命名规范

和Java 编码的理念一样,在项目中始终用清晰的,描述性的,一致的命名规范对开发人员理解XML配置非常有用。拿bean ID举例来说,你可以遵循Java类中属性的命名规范。比如说,OrderServiceDAO的bean ID应该是orderServiceDAO。对于大项目来说,在bean ID前加包名来作为前缀。

 

3.使用简化格式

简化格式有利于减少冗余,因为它把属性值和引用作为属性,而不是子元素。看下面的例子:

<bean id=”orderService”

class=”com.lizjason.spring.OrderService”>

<property name=”companyName”>

<value>lizjason</value>

</property>

<constructor-arg>

<ref bean=”orderDAO”>

</constructor-arg>

</bean>

以上程序可以重新以简化格式书写为:

<bean id=”orderService”

class=”com.lizjason.spring.OrderService”>

<property name=”companyName”

value=”lizjason”/>

<constructor-arg ref=”orderDAO”/>

</bean>

简化格式在1.2版本时已经可用了,但请注意不存在<ref local=”…”>这种简化格式不仅可以较少你的代码输入量,而且可以使XML配置更加的清晰。当你的配置文件中存在大量的bean定义时,它可以显著地提高可读性。

 

4.尽量使用type而不是index去解决构造函数参数的匹配问题

当构造函数中有多个同类型的参数时,Spring只允许你使用从0开始的index或者value标签来解决这个问题。请看下面的例子:

<bean id=”billingService”

class=”com.lizjason.spring.BillingService”>

<constructor-arg index=”0″ value=”lizjason”/>

<constructor-arg index=”1″ value=”100″/>

</bean>

最好用type属性取代上面的做法:

<bean id=”billingService”

class=”com.lizjason.spring.BillingService”>

<constructor-arg type=”java.lang.String”

value=”lizjason”/>

<constructor-arg type=”int” value=”100″/>

</bean>

 

用index可以稍微减少冗余,但是它更容易出错且不如type属性可读性高。你应该仅在构造函数中有参数冲突时使用index。

 

5.如可能,尽量复用bean定义

Spring 提供了一种类似于继承的机制来降低配置信息的重复并使XML配置更加的简单。一个子bean可以从它的父bean继承配置信息,本质上这个父bean就像 它的子bean的一个模板。这是一个在大型项目中必须使用的特性。所有你要做的就是把父bean的abstract属性置为true,并在子bean中加 以引用。例如:

<bean id=”abstractService” abstract=”true”

class=”com.lizjason.spring.AbstractService”>

<property name=”companyName”

value=”lizjason”/>

</bean>

 

<bean id=”shippingService”

parent=”abstractService”

class=”com.lizjason.spring.ShippingService”>

<property name=”shippedBy” value=”lizjason”/>

</bean>

shippingService bean继承了abstractService bean的属性companyName的值lizjason。注意,如果你为bean声名一个class或工厂方法,这个bean将会默认为abstract

 

6.尽量使用ApplicationContext装配bean,而不是用import

像Ant脚本中imports一样,Spring的import 元素对于模块化bean的装配非常有用,例如:

<beans>

<import resource=”billingServices.xml”/>

<import resource=”shippingServices.xml”/>

<bean id=”orderService”

class=”com.lizjason.spring.OrderService”/>

<beans>

然而,比起在XML中用imports预装配这些bean,利用ApplicationContext来配置它们将更加灵活,也可以使XML配置更加的易于管理。你可以像下面这样传递一个bean定义数组到ApplicationContext的构造函数中:

String[] serviceResources =

{“orderServices.xml”,

“billingServices.xml”,

“shippingServices.xml”};

ApplicationContext orderServiceContext = new

ClassPathXmlApplicationContext(serviceResources);

 

7.用id来标识bean

你可以用id 或名字作为bean的标识。用id可读性较差,但是它可以影响XML分析器使bean的reference有效。如果id由于XML IDREF约束而无法使用,你可以用name作为bean的标识。XML IDREF约束是指id必须以字母开始(或者是在XML声名了的一个标点符号),后面可以是字母,数字,连字符,下划线,冒号或full stops(不知道怎么翻译好)。在实际应用中很少会遇到XML IDREF约束问题。

 

8.在开发阶段使用依赖检查

你可以为bean的dependency-check属性设置一个值来取代默认的none,比如说simple,objects或者all,这样的话容器将替你做依赖有效性的检查。当一个bean的所有属性(或者某些属性目录)都被明确设置,或利用自动装配时将会非常有用。

<bean id=”orderService”

class=”com.lizjason.spring.OrderService”

dependency-check=”objects”>

<property name=”companyName”

value=”lizjason”/>

<constructor-arg ref=”orderDAO”/>

</bean>

在这个例子中,容器将确保这些属性不是privitives或者保证collections是为orderService bean设置的。为所有的bean设置默认的依赖检查是可能的,但这个特性由于有些bean的属性不需要设置而很少使用。

 

9.为每个配置文件加一个描述注释

在XML配置文件中最好使用有描述性的id和name,而不是成堆的注释。另外,加一个文件描述头将会非常有用,这个描述可以概括文件中定义的bean。另一个选择,你可以在description元素中加入描述信息。例如:

<beans>

<description>

This file defines billing service

related beans and it depends on

baseServices.xml,which provides

service bean templates…

</description>

</beans>

用description元素的一个好处就是工具可以很容易的把描述信息从这个元素中提取出来。

 

10.   和team members沟通变更

当你修改java源码后,要确保更改了配置文件中的相应部分并把这个情况告知你的team members。XML配置文件也是代码,它们是程序的重要组成部分,但它们很难阅读和维护。大多数时间里,你需要同时看XML配置文件和java代码才能知道是怎么回事。

 

11.   setter注入和构造函数注入,优先使用前者

Spring提供了三种注入方式:构造函数注入,setter注入和方法注入。一般我们使用前两种。

<bean id=”orderService”

class=”com.lizjason.spring.OrderService”>

<constructor-arg ref=”orderDAO”/>

</bean>

 

<bean id=”billingService”

class=”com.lizjason.spring.BillingService”>

<property name=”billingDAO”

ref=”billingDAO”>

</bean>

在这个例子中,orderService bean用了构造函数注入,而BillingService bean用了setter注入。构造函数注入可以确保bean正确地构建,但是setter注入更加的灵活和易于控制,特别是当class有多个属性并且它们中的一些是可选的情况是更是如此。

 

12.   不要滥用注入

就像前面提到的,Spring的ApplicationContextEclipse and IntelliJ,java代码更加的易于阅读,维护和管理比使XML文件可以替你创建java对象,但不是所有的java对象都应该通过注入创建。例如,域对象就不应该通过ApplicationContext创建。Spring是一个优秀的框架,但是考虑到可读性和可操控性,基于XML配置的配置会在定义很多bean的时候出现麻烦。过渡使用依赖注入将会使XML配置更加的复杂和冗长。切记,当使用高效的IDE时,例如

 

结论

XML是Spring 流行的配置格式。存在大量bean定义时,基于XML的配置会变得冗长而不易使用。Spring提供了丰富的配置选项。适当地使用这些选项可以使XML配 置更加的清晰,但其它的一些选项,例如自动装配,可能会降低可读性和可维护性。参考本文中提到的这些技巧可能会帮助你创建干净而易读的XML配置文件

 

 

 

<bean

 

id=”beanId”(1)

 

name=”beanName”(2)

 

class=”beanClass”(3)

 

parent=”parentBean”(4)

 

abstract=”true | false”(5)

 

singleton=”true | false”(6)

 

lazy-init=”true | false | default”(7)

 

autowire=”no | byName | byType | constructor | autodetect | default”(8)

 

dependency-check = “none | objects | simple | all | default”(9)

 

depends-on=”dependsOnBean”(10)

 

init-method=”method”(11)

 

destroy-method=”method”(12)

 

factory-method=”method”(13)

 

factory-bean=”bean”>(14)

 

</bean>

 

 

(1)、id: Bean的唯一标识名。它必须是合法的XML ID,在整个XML文档中唯一。

 

(2)、name: 用来为id创建一个或多个别名。它可以是任意的字母符合。多个别名之间用逗号或空格分开。

 

(3)、class: 用来定义类的全限定名(包名+类名)。只有子类Bean不用定义该属性。

 

(4)、parent: 子类Bean定义它所引用它的父类Bean。这时前面的class属性失效。子类Bean会继承父类Bean的所有属性,子类Bean也可以覆盖父类Bean的属性。注意:子类Bean和父类Bean是同一个Java类。

 

(5)、abstract(默认为”false”):用来定义Bean是否为抽象Bean。它表示这个Bean将不会被实例化,一般用于父类Bean,因为父类Bean主要是供子类Bean继承使用。

 

(6)、singleton(默认为“true”):定义Bean是否是Singleton(单例)。如果设为“true”,则在BeanFactory作用范围内,只维护此Bean的一个实例。如果设为“flase”,Bean将是Prototype(原型)状态,BeanFactory将为每次Bean请求创建一个新的Bean实例。

 

(7)、lazy-init(默认为“default”):用来定义这个Bean是否实现懒初始化。如果为“true”,它将在BeanFactory启动时初始化所有的Singleton Bean。反之,如果为“false”,它只在Bean请求时才开始创建Singleton Bean。

 

(8)、autowire(自动装配,默认为“default”):它定义了Bean的自动装载方式。

 

1、“no”:不使用自动装配功能。

 

2、“byName”:通过Bean的属性名实现自动装配。

 

3、“byType”:通过Bean的类型实现自动装配。

 

4、“constructor”:类似于byType,但它是用于构造函数的参数的自动组装。

 

5、“autodetect”:通过Bean类的反省机制(introspection)决定是使用“constructor”还是使用“byType”。

 

(9)、dependency-check(依赖检查,默认为“default”):它用来确保Bean组件通过JavaBean描述的所以依赖关系都得到满足。在与自动装配功能一起使用时,它特别有用。

 

1、 none:不进行依赖检查。

 

2、 objects:只做对象间依赖的检查。

 

3、 simple:只做原始类型和String类型依赖的检查

 

4、 all:对所有类型的依赖进行检查。它包括了前面的objects和simple。

 

(10)、depends-on(依赖对象):这个Bean在初始化时依赖的对象,这个对象会在这个Bean初始化之前创建。

 

(11)、init-method:用来定义Bean的初始化方法,它会在Bean组装之后调用。它必须是一个无参数的方法。

 

(12)、destroy-method:用来定义Bean的销毁方法,它在BeanFactory关闭时调用。同样,它也必须是一个无参数的方法。它只能应用于singleton Bean。

 

(13)、factory-method:定义创建该Bean对象的工厂方法。它用于下面的“factory-bean”,表示这个Bean是通过工厂方法创建。此时,“class”属性失效。

 

(14)、factory-bean:定义创建该Bean对象的工厂类。如果使用了“factory-bean”则“class”属性失效。

 

 

 

 

 

 

 

下面列出<ref>元素的所有可用的指定方式:

 

bean:可以在当前文件中查找依赖对象,也可以在应用上下文(ApplicationContext)中查找其它配置文件的对象。

 

local:只在当前文件中查找依赖对象。这个属性是一个XML IDREF,所以它指定的对象必须存在,否则它的验证检查会报错。

 

external:在其它文件中查找依赖对象,而不在当前文件中查找。

 

总的来说,<ref bean=”…”/>和<ref local=”…”/>大部分的时候可以通用。“bean”是最灵活的方式,它允许你在多个文件之间共享Bean。而“local”则提供了便利的XML验证。

 

 

 

如何使用spring的作用域:

<bean id=”role” scope=”singleton”/>

这里的scope就是用来配置spring bean的作用域,它标识bean的作用域。

在spring2.0之前bean只有2种作用域即:singleton(单例)、non-singleton(也称 prototype), Spring2.0以后,增加了session、request、global session三种专用于Web应用程序上下文的Bean。因此,默认情况下Spring2.0现在有五种类型的Bean。当然,Spring2.0对 Bean的类型的设计进行了重构,并设计出灵活的Bean类型支持,理论上可以有无数多种类型的Bean,用户可以根据自己的需要,增加新的Bean类 型,满足实际应用需求。

1、singleton作用域

当一个bean的作用域设置为singleton, 那么Spring IOC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。换言之,当把 一个bean定义设置为singleton作用域时,Spring IOC容器只会创建该bean定义的唯一实例。这个单一实例会被存储到单例缓存(singleton cache)中,并且所有针对该bean的后续请求和引用都 将返回被缓存的对象实例,这里要注意的是singleton作用域和GOF设计模式中的单例是完全不同的,单例设计模式表示一个ClassLoader中 只有一个class存在,而这里的singleton则表示一个容器对应一个bean,也就是说当一个bean被标识为singleton时 候,spring的IOC容器中只会存在一个该bean。

配置实例:

<bean id=”role” scope=”singleton”/>

或者

<bean id=”role” singleton=”true”/>

2、prototype

prototype作用域部署的bean,每一次请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)都会产生一个新的bean实例,相当与一个new的操作,对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责,容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法,而对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。 清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责。(让Spring容器释放被singleton作用域bean占用资源的一种可行方式是,通过使用 bean的后置处理器,该处理器持有要被清除的bean的引用。)

配置实例:

<bean id=”role” scope=”prototype”/>

或者

<beanid=”role” singleton=”false”/>

3、request

request表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP request内有效,配置实例:

request、session、global session使用的时候首先要在初始化web的web.xml中做如下配置:

如果你使用的是Servlet 2.4及以上的web容器,那么你仅需要在web应用的XML声明文件web.xml中增加下述ContextListener即可:

<web-app>

<listener>

<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>

</listener>

</web-app>

 

 

,如果是Servlet2.4以前的web容器,那么你要使用一个javax.servlet.Filter的实现:

<web-app>

..

<filter>

<filter-name>requestContextFilter</filter-name>

<filter-class>org.springframework.web.filter.RequestContextFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>requestContextFilter</filter-name>

<url-pattern>/*</url-pattern>

</filter-mapping>

</web-app>

 

 

接着既可以配置bean的作用域了:

<bean id=”role” scope=”request”/>

4、session

session作用域表示该针对每一次HTTP请求都会产生一个新的bean,同时该bean仅在当前HTTP session内有效,配置实例:

配置实例:

和request配置实例的前提一样,配置好web启动文件就可以如下配置:

<bean id=”role” scope=”session”/>

5、global session

global session作用域类似于标准的HTTP Session作用域,不过它仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个 portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。如果你在web中使用global session作用域来标识bean,那么web会自动当成session类型来使用。

配置实例:

和request配置实例的前提一样,配置好web启动文件就可以如下配置:

<bean id=”role” scope=”global session”/>

6、自定义bean装配作用域

在spring2.0中作用域是可以任意扩展的,你可以自定义作用域,甚至你也可以重新定义已有的作用域(但是你不能覆盖singleton和 prototype),spring的作用域由接口org.springframework.beans.factory.config.Scope来定 义,自定义自己的作用域只要实现该接口即可,下面给个实例:

我们建立一个线程的scope,该scope在表示一个线程中有效,代码如下:

publicclass MyScope implements Scope {

privatefinal ThreadLocal threadScope = new ThreadLocal() {

protected Object initialValue() {

returnnew HashMap();

}

};

public Object get(String name, ObjectFactory objectFactory) {

Map scope = (Map) threadScope.get();

Object object = scope.get(name);

if(object==null) {

object = objectFactory.getObject();

scope.put(name, object);

}

return object;

}

public Object remove(String name) {

Map scope = (Map) threadScope.get();

return scope.remove(name);

}

publicvoid registerDestructionCallback(String name, Runnable callback) {

}

public String getConversationId() {

// TODO Auto-generated method stub

returnnull;

}

}

spring 3.0 应用springmvc 构造RESTful URL 详细讲解(转)

 rest, spring  spring 3.0 应用springmvc 构造RESTful URL 详细讲解(转)已关闭评论
2月 272013
 

转自:http://www.blogjava.net/badqiu/archive/2009/09/22/296082.html

springmvc 3.0 中增加 RESTful URL功能,构造出类似javaeye现在的URL。 rest介绍

比如如下URL

Java代码
  1. /blog/1  HTTP GET =>    得到id = 1的blog
  2. /blog/1  HTTP DELETE => 删除 id = 1的blog
  3. /blog/1  HTTP PUT  =>   更新id = 1的blog
  4. /blog     HTTP POST =>   新增BLOG

 

 

以下详细解一下spring rest使用.

 

 

首先,我们带着如下三个问题查看本文。

1. 如何在java构造没有扩展名的RESTful url,如 /forms/1,而不是 /forms/1.do

2. 由于我们要构造没有扩展名的url本来是处理静态资源的容器映射的,现在被我们的spring占用了,冲突怎么解决?

3. 浏览器的form标签不支持提交delete,put请求,如何曲线解决?

 

 

springmvc rest 实现

springmvc的resturl是通过@RequestMapping 及@PathVariable annotation提供的,通过如@RequestMapping(value=”/blog/{id}”,method=RequestMethod.DELETE)即可处理/blog/1 的delete请求.

Java代码

@RequestMapping(value=”/blog/{id}”,method=RequestMethod.DELETE)
public ModelAndView delete(@PathVariable Long id,HttpServletRequest request,HttpServletResponse response) {
blogManager.removeById(id);
return new ModelAndView(LIST_ACTION);
}

 

@RequestMapping @PathVariable如果URL中带参数,则配合使用,如

Java代码@RequestMapping(value=”/blog/{blogId}/message/{msgId}”,method=RequestMethod.DELETE)
public ModelAndView delete(@PathVariable(“blogId”) Long blogId,@PathVariable(“msgId”) Long msgId,HttpServletRequest request,HttpServletResponse response) {
}

 

 spring rest配置指南

1. springmvc web.xml配置

Xml代码

<!– 该servlet为tomcat,jetty等容器提供,将静态资源映射从/改为/static/目录,如原来访问 http://localhost/foo.css ,现在http://localhost/static/foo.css –>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/static/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

<!– URL重写filter,用于将访问静态资源http://localhost/foo.css 转为http://localhost/static/foo.css –>
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
<init-param>
<param-name>confReloadCheckInterval</param-name>
<param-value>60</param-value>
</init-param>
<init-param>
<param-name>logLevel</param-name>
<param-value>DEBUG</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

<!– 覆盖default servlet的/, springmvc servlet将处理原来处理静态资源的映射 –>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

<!– 浏览器不支持put,delete等method,由该filter将/blog?_method=delete转换为标准的http delete方法 –>
<filter>
<filter-name>HiddenHttpMethodFilter</filter-name>
<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
</filter>

<filter-mapping>
<filter-name>HiddenHttpMethodFilter</filter-name>
<servlet-name>springmvc</servlet-name>
</filter-mapping>

 

2. webapp/WEB-INF/springmvc-servlet.xml配置,使用如下两个class激活@RequestMapping annotation

Java代码

<bean class=”org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping”/>
<bean class=”org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter”/>

 

完整配置

Java代码

<beans default-autowire=”byName” >

<!– 自动搜索@Controller标注的类 –>
<context:component-scan base-package=”com.**.controller”/>

<bean class=”org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping”/>

<bean class=”org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter”/>

<!– Default ViewResolver –>
<bean id=”viewResolver” class=”org.springframework.web.servlet.view.InternalResourceViewResolver”>
<property name=”viewClass” value=”org.springframework.web.servlet.view.JstlView”/>
<property name=”prefix” value=”/pages”/>
<property name=”suffix” value=”.jsp”></property>
</bean>

<bean id=”messageSource” class=”org.springframework.context.support.ResourceBundleMessageSource” p:basename=”i18n/messages”/>

<!– Mapping exception to the handler view –>
<bean id=”exceptionResolver” class=”org.springframework.web.servlet.handler.SimpleMappingExceptionResolver”>
<!– to /commons/error.jsp –>
<property name=”defaultErrorView” value=”/commons/error”/>
<property name=”exceptionMappings”>
<props>
</props>
</property>
</bean>

</beans>

 

3. Controller编写

Java代码

/**
* @RequestMapping(“/userinfo”) 具有层次关系,方法级的将在类一级@RequestMapping之一,
* 如下面示例, 访问方法级别的@RequestMapping(“/new”),则URL为 /userinfo/new
*/
@Controller
@RequestMapping(“/userinfo”)
public class UserInfoController extends BaseSpringController{
//默认多列排序,example: username desc,createTime asc
protected static final String DEFAULT_SORT_COLUMNS = null;

private UserInfoManager userInfoManager;

private final String LIST_ACTION = “redirect:/userinfo”;

/**
* 通过spring自动注入
**/
public void setUserInfoManager(UserInfoManager manager) {
this.userInfoManager = manager;
}

/** 列表 */
@RequestMapping
public ModelAndView index(HttpServletRequest request,HttpServletResponse response,UserInfo userInfo) {
PageRequest<Map> pageRequest = newPageRequest(request,DEFAULT_SORT_COLUMNS);
//pageRequest.getFilters(); //add custom filters

Page page = this.userInfoManager.findByPageRequest(pageRequest);
savePage(page,pageRequest,request);
return new ModelAndView(“/userinfo/list”,”userInfo”,userInfo);
}

/** 进入新增 */
@RequestMapping(value=”/new”)
public ModelAndView _new(HttpServletRequest request,HttpServletResponse response,UserInfo userInfo) throws Exception {
return new ModelAndView(“/userinfo/new”,”userInfo”,userInfo);
}

/** 显示 */
@RequestMapping(value=”/{id}”)
public ModelAndView show(@PathVariable Long id,HttpServletRequest request,HttpServletResponse response) throws Exception {
UserInfo userInfo = (UserInfo)userInfoManager.getById(id);
return new ModelAndView(“/userinfo/show”,”userInfo”,userInfo);
}

/** 编辑 */
@RequestMapping(value=”/{id}/edit”)
public ModelAndView edit(@PathVariable Long id,HttpServletRequest request,HttpServletResponse response) throws Exception {
UserInfo userInfo = (UserInfo)userInfoManager.getById(id);
return new ModelAndView(“/userinfo/edit”,”userInfo”,userInfo);
}

/** 保存新增 */
@RequestMapping(method=RequestMethod.POST)
public ModelAndView create(HttpServletRequest request,HttpServletResponse response,UserInfo userInfo) throws Exception {
userInfoManager.save(userInfo);
return new ModelAndView(LIST_ACTION);
}

/** 保存更新 */
@RequestMapping(value=”/{id}”,method=RequestMethod.PUT)
public ModelAndView update(@PathVariable Long id,HttpServletRequest request,HttpServletResponse response) throws Exception {
UserInfo userInfo = (UserInfo)userInfoManager.getById(id);
bind(request,userInfo);
userInfoManager.update(userInfo);
return new ModelAndView(LIST_ACTION);
}

/** 删除 */
@RequestMapping(value=”/{id}”,method=RequestMethod.DELETE)
public ModelAndView delete(@PathVariable Long id,HttpServletRequest request,HttpServletResponse response) {
userInfoManager.removeById(id);
return new ModelAndView(LIST_ACTION);
}

/** 批量删除 */
@RequestMapping(method=RequestMethod.DELETE)
public ModelAndView batchDelete(@RequestParam(“items”) Long[] items,HttpServletRequest request,HttpServletResponse response) {

for(int i = 0; i < items.length; i++) {

userInfoManager.removeById(items[i]);
}
return new ModelAndView(LIST_ACTION);
}

}

 

上面是rapid-framework 新版本生成器生成的代码,以后也将应用此规则,rest url中增删改查等基本方法与Controller的方法映射规则

Java代码

/userinfo => index()
/userinfo/new => _new()
/userinfo/{id} => show()
/userinfo/{id}/edit => edit()
/userinfo POST => create()
/userinfo/{id} PUT => update()
/userinfo/{id} DELETE => delete()
/userinfo DELETE => batchDelete()

 注(不使用 /userinfo/add  => add() 方法是由于add这个方法会被maxthon浏览器当做广告链接过滤掉,因为包含ad字符)

 

4. jsp 编写

Html代码

<form:form action=”${ctx}/userinfo/${userInfo.userId}” method=”put”>
</form:form>

 生成的html内容如下, 生成一个hidden的_method=put,并于web.xml中的HiddenHttpMethodFilter配合使用,在服务端将post请求改为put请求
Java代码

<form id=”userInfo” action=”/springmvc_rest_demo/userinfo/2″ method=”post”>
<input type=”hidden” name=”_method” value=”put”/>
</form>

 

另外一种方法是你可以使用ajax发送put,delete请求.

 

5. 静态资源的URL重写

如上我们描述,现因为将default servlet映射至/static/的子目录,现我们访问静态资源将会带一个/static/前缀.

如 /foo.gif, 现在访问该文件将是 /static/foo.gif.
那如何避免这个前缀呢,那就是应用URL rewrite,现我们使用 http://tuckey.org/urlrewrite/, 重写规则如下

 

Xml代码

<urlrewrite>
<!– 访问jsp及jspx将不rewrite url,其它.js,.css,.gif等将重写,如 /foo.gif => /static/foo.gif –>
<rule>
<condition operator=”notequal” next=”and” type=”request-uri”>.*.jsp</condition>
<condition operator=”notequal” next=”and” type=”request-uri”>.*.jspx</condition>
<from>^(/.*..*)$</from>
<to>/static$1</to>
</rule>
</urlrewrite>