AOP的原理已经不是什么秘密.
代理实现更是很多年前就有的事..
在Spring中,基于Java动态代理,但这个必须基于接口.
所在在Spring中还有基于类的的代理,就是使用了CGLIB.
更多的可以参考http://www.redsaga.com/spring_ref/2.5/html/aop-api.html
声明式事务就是基于AOP实现,轻量级容器带来的基础设施!
使用Spring中的工厂bean : TransactionProxyFactoryBean
注解的使用更是方便
在配置文件中加入
<tx:annotation-driven transaction-manager="txManager"/>
[quote]实际上,如果你用 'transactionManager' 来定义 PlatformTransactionManager bean的名字的话,你就可以忽略 <tx:annotation-driven/> 标签里的 'transaction-manager' 属性。 如果 PlatformTransactionManager bean你要通过其它名称来注入的话,你必须用 'transaction-manager' 属性来指定它[/quote]
[quote]@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。 然而,请注意只是使用 @Transactional 注解并不会启用事务行为, 它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 <tx:annotation-driven/>元素的出现 开启 了事务行为。
Spring团队的建议是你只在具体的类上使用 @Transactional 注解, 而不要注解在接口上。你当然可以在接口(或接口方法)上使用 @Transactional 注解, 但是这只有在你使用基于接口的代理时它才会生效。因为注解是 不能继承 的, 这就意味着如果你正在使用基于类的代理时,事务的设置将不能被基于类的代理所识别,而且对象也不会被事务代理所包装 (这是很糟糕的)。 因此,请接受Spring团队的建议,在具体的类(包括该类的方法)上使用 @Transactional 注解。
注意:[color=red]在代理模式下(默认的情况),只有从代理传过来的‘外部’方法调用才会被拦截。 这就意味着‘自我调用’是不会触发事务的,比如说,一个在目标对象中调用目标对象其他方法的方法是不会触发一个事务的,即使这个方法被标记为 @Transactional![/color]
如果你期望‘自我调用’被事务覆盖到,可以考虑使用AspectJ 模式(如下所示)。在这种情况下,一开始就没有任何代理的存在; 为了把@Transactional的方法变成运行时的行为,目标类会被‘编织’起来(比如修改它的字节码)。 [/quote]
是运用JAVA动态代理还是使用CGLIB可以配置
[quote]在<tx:annotation-driven/>元素上的"proxy-target-class" 属性 控制了有什么类型的事务性代理会为使用@Transactional 来注解的类创建代理。 如果"proxy-target-class" 属性被设为"true",那么基于类的代理就会被创建。 如果"proxy-target-class" 属性被设为"false" 或者没设,那么会创建基于接口的标准JDK代理[/quote]
----------------------------------------------------------------
[size=large]注意点:[/size]在代理模式下(默认的情况),只有从代理传过来的‘外部’方法调用才会被拦截。 这就意味着‘自我调用’是不会触发事务的,比如说,一个在目标对象中调用目标对象其他方法的方法是不会触发一个事务的,即使这个方法被标记为 @Transactional!
[quote]cglib是继承原来的类,jdk proxy是继承Proxy类,返回的是一个新的"包装"过的类,但原来Object方法中(super中)的调用还是属于super中的[/quote]
也就是说AOP不支持嵌套
http://www.iteye.com/topic/47879
一个类的方法调用另一个方法,是不能增强的.Spring中使用基于接口和类的实现,实际上我们使用的是增强后的子类,如果直接调用就只是调用了原始方法,没有做到增强...
以上代码中如果把(1)处的注解注释掉,那么就会出现
原因是这儿直接原始调用,并不是调用增强类的方法..
在上面的示例中,可以把(2)处的注解去掉,但(1)处的绝对不再去掉....
因为外部在调用getArticleView方法时,其实是执行增强过的方法.所以可以完成更新事务.
代理实现更是很多年前就有的事..
在Spring中,基于Java动态代理,但这个必须基于接口.
所在在Spring中还有基于类的的代理,就是使用了CGLIB.
更多的可以参考http://www.redsaga.com/spring_ref/2.5/html/aop-api.html
声明式事务就是基于AOP实现,轻量级容器带来的基础设施!
使用Spring中的工厂bean : TransactionProxyFactoryBean
注解的使用更是方便
在配置文件中加入
<tx:annotation-driven transaction-manager="txManager"/>
[quote]实际上,如果你用 'transactionManager' 来定义 PlatformTransactionManager bean的名字的话,你就可以忽略 <tx:annotation-driven/> 标签里的 'transaction-manager' 属性。 如果 PlatformTransactionManager bean你要通过其它名称来注入的话,你必须用 'transaction-manager' 属性来指定它[/quote]
[quote]@Transactional 注解可以被应用于接口定义和接口方法、类定义和类的 public 方法上。 然而,请注意只是使用 @Transactional 注解并不会启用事务行为, 它仅仅 是一种元数据,能够被可以识别 @Transactional 注解和上述的配置适当的具有事务行为的beans所使用。上面的例子中,其实正是 <tx:annotation-driven/>元素的出现 开启 了事务行为。
Spring团队的建议是你只在具体的类上使用 @Transactional 注解, 而不要注解在接口上。你当然可以在接口(或接口方法)上使用 @Transactional 注解, 但是这只有在你使用基于接口的代理时它才会生效。因为注解是 不能继承 的, 这就意味着如果你正在使用基于类的代理时,事务的设置将不能被基于类的代理所识别,而且对象也不会被事务代理所包装 (这是很糟糕的)。 因此,请接受Spring团队的建议,在具体的类(包括该类的方法)上使用 @Transactional 注解。
注意:[color=red]在代理模式下(默认的情况),只有从代理传过来的‘外部’方法调用才会被拦截。 这就意味着‘自我调用’是不会触发事务的,比如说,一个在目标对象中调用目标对象其他方法的方法是不会触发一个事务的,即使这个方法被标记为 @Transactional![/color]
如果你期望‘自我调用’被事务覆盖到,可以考虑使用AspectJ 模式(如下所示)。在这种情况下,一开始就没有任何代理的存在; 为了把@Transactional的方法变成运行时的行为,目标类会被‘编织’起来(比如修改它的字节码)。 [/quote]
是运用JAVA动态代理还是使用CGLIB可以配置
[quote]在<tx:annotation-driven/>元素上的"proxy-target-class" 属性 控制了有什么类型的事务性代理会为使用@Transactional 来注解的类创建代理。 如果"proxy-target-class" 属性被设为"true",那么基于类的代理就会被创建。 如果"proxy-target-class" 属性被设为"false" 或者没设,那么会创建基于接口的标准JDK代理[/quote]
----------------------------------------------------------------
[size=large]注意点:[/size]在代理模式下(默认的情况),只有从代理传过来的‘外部’方法调用才会被拦截。 这就意味着‘自我调用’是不会触发事务的,比如说,一个在目标对象中调用目标对象其他方法的方法是不会触发一个事务的,即使这个方法被标记为 @Transactional!
[quote]cglib是继承原来的类,jdk proxy是继承Proxy类,返回的是一个新的"包装"过的类,但原来Object方法中(super中)的调用还是属于super中的[/quote]
也就是说AOP不支持嵌套
http://www.iteye.com/topic/47879
一个类的方法调用另一个方法,是不能增强的.Spring中使用基于接口和类的实现,实际上我们使用的是增强后的子类,如果直接调用就只是调用了原始方法,没有做到增强...
@Transactional //(1)
public ArticleView getArticleView(String articleId) {
Article article = articleDao.query(IntegerUtil.parseInt(articleId));
article.setHot(article.getHot()+1);
updateArticle(article);
return articleRepository.buildArticleView(articleId);
}
@Transactional //(2)
public void updateArticle(Article article) {
// TODO Auto-generated method stub
articleDao.update(article);
}
以上代码中如果把(1)处的注解注释掉,那么就会出现
Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
异常.
原因是这儿直接原始调用,并不是调用增强类的方法..
在上面的示例中,可以把(2)处的注解去掉,但(1)处的绝对不再去掉....
因为外部在调用getArticleView方法时,其实是执行增强过的方法.所以可以完成更新事务.