- 浏览: 103110 次
- 性别:
- 来自: 杭州
最新评论
让Spring架构减化事务配置
Spring颠覆了以前的编程模式,引入了IOC等全新的概念,广受大家的喜爱。目前大多数j2ee项目都已经采用Spring框架。Spring最大的问题是太多的配置文件,使得你不仅需要维护程序代码,还需要额外去维护相关的配置文件。最典型的就是事务配置(注:这里的“事务配置”都指“声明式事务配置”),在Spring中进行事务配置除了定义对象自身的bean外,还需要定义一个进行事务代理的bean.如果你有n个类需要引入事务,那么你就必须定义2n个bean。维护这些bean的代价是十分昂贵的,所以必须要对事务配置进行减化。如果你是基于Spring进行架构设计,那么作为一个好的架构设计师,应该把一些公共的方面进行简化,让项目的开发人员只关心项目的业务逻辑,而不要花费太多的精力去关心业务逻辑之外的太多东西。所以作为一个好的架构就应该把事务管理进行简化,让程序员花在编程之外的工作最小化。
1. Spring声明式事务配置的几种方法
在Spring中进行事务控制首先要选择适当的事务管理器,其次为程序选择划分事务的策略。如果只有单个事务性资源,可以从“单一资源”的PlatformTransactionManger实现当中选择一个,这些实现有:DataSourceTransactionManager,HibernateTransactionManager, JdoTransactionManager,PersistenceBrokerTransactionManager和JmsTransactionManager。根据你所采用的数据库持久化技术选择。如果你的项目运行于支持JTA的服务器,那么将选择JtaTransactionManger,将会支持多资源事务。
下表将为你选择适当的事务管理器提供参考。
技术 事务管理器 内建的事务支持
JDBC DataSurceTransactionManagerJtaTransactionManager JdbcTemplate和org.springframework.jdbc.object包中的所有类
IBATIS DataSourceTransactionManagerJtaTransactionManager SqlMapClientTemplate和SqlClientTemplate
Hibernate HibernateTransactionManagerJtaTransactionManager HibernateTemplate和HibernateInterceptor
JDO JdoTransactionManagerJtaTransactionManager JdoTemplate和JdoInterceptor
ApacheOJB PersistenceBrokerTransactionManagerJtaTransactionManager PersistenceBrokerTemplate
JMS JmsTransactionManager JmsTemplate
在划分事务时,我们需要进行事务定义,也就是配置事务的属性。事务的属性有传播行业,隔离级别,超时值及只读标志。TransactionAttribute接口指定哪些异常将导致一个回滚,哪些应该一次性提交。
(1) 使用ProxyFactoryBean 和TransactionInterceptor
class="org.springframework.transaction.interceptor.TransactionInterceptor">
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
ref="com.prs.application.ehld.sample.biz.service.sampleService.target">
transactionInterceptor
通过ProxyFacgtoryBean和TransactionInterceptor组合使用,可以对事务进行更多的控制。所有需要事务控制的对象可以共享一个transactionInterceptor的事务属性。
(2) 使用TransactionProxyFactoryBean
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
abstract="true">
ref="com.prs.application.ehld.sample.biz.service.sampleService.target" />
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
使用TransactionProxyFactoryBean需要为每一个代理对象都去定义自己的事务属性。
(3) 使用TransactionProxyFactoryBean及abstract属性来简化配置
这种方工也是目前使用得最多的一种声明式事务配置方法
abstract="true">
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
ref="com.prs.application.ehld.sample.biz.service.sampleService.target">
使用abstract属性,可以让代理对象可以共享一个定义好的事务属性,使配置简化。
(4)使用BeanNameAutoProxyCreator
class="org.springframework.transaction.interceptor.TransactionInterceptor">
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
transactionInterceptor
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
使用BeanNameAutoProxyCreator可以由框架来提供适当的代理,由一个transactionInterceptor统一定义事务属性,只需要把需要事务控制的bean加到beannames的列表。
对于需要大量声明式事务的bean,BeanNameAutoProxyCreator是十分方便的。减少了代理bean的定义,还可以灵活的决定一个bean是否进行事务控制。
上面四种方法是在Spring中常见的声明式事务配置方法,其中使用TransactionProxyFactoryBean及abstract属性进行配置是最常见的简化方法。
我们暂且把需要进行事务控制的bean叫事务bean.把依赖和调用它的bean叫做业务bean。对事务bean进行代理叫做事务代理bean.
1. 使用ProxyFactoryBean 和TransactionInterceptor,可以由一个TransactionInterceptor统一定义事务属性,对于每一个事务bean都需要再定义一个事务代理bean。如果有n个事务bean,那么就需要定义和维护2n个bean。并且注入到业务bean的不是事务bean本身,而是要求用事务代理bean注入。这增加了理解的难度。
2. 使用TransactionProxyFactoryBean需要为每一个事务代理bean都定义自己的事务属性,除了需要维护2n个bean外,还需要为每一个事务代理bean定义事务属性。可以说是最麻烦的。同样需要把事务代理bean注入到业务bean,增加了理解的难度和项目的复杂度。
3. 使用TransactionProxyFactoryBean及abstract属性是对使用TransactionProxyFactoryBean的一种简单化配置,可以让所有的事务bean共享一致的事务属性定义。需要维护2n个bean,需要把事务代理bean注入到业务bean。
4. 使用BeanNameAutoProxyCreator最适合在框架中使用,只需要维护n个bean。也无需要事务代理bean。直接把事务bean注入业务bean中。但是它必须把需要事务控制的bean加到beanNames列表中。
2.类型自动代理创建器BeanClassTypeAutoProxyCreator
得于BeanNameAutoProxyCreator的启示,BeanNameAutoProxyCreator可以实现框架来实现自动代理。它只是把需要代理的bean加入beanNames属性列表。大大的简化了代理的配置,减少了代理bean的定义,使用事务bean注入业务对象,而不是代理bean注入,更合乎事务逻辑。BeanNameAutoProxyCreator仍然需要开发人员除了定义业务bean外,还需要关心事务的定义,当然已经简单了很多。如果能实现一个BeanClassTypeAutoProxyCreator,为它指定一个可以代理的ClassType列表,那么在context中所有属于ClassType和其子类的bean都自动获得代理。
实现思路:
1.BeanNameAutoProxyCreator继承了AbstractAutoProxyCreator,去实现方法:
protected abstract Object[] getAdvicesAndAdvisorsForBean(
Class beanClass, String beanName, TargetSource customTargetSource)
在BeanNameAutoProxyCreator中的实现是判断beanName 是存在于beanNames列表,如果能找到则Object[]不对空。否则返回null。
所以BeanClassTypeAutoProxyCreator也应该继承AbstractAutoProxyCreator。
getAdvicesAndAdvisorsForBean方法的实现可以参照BeanNameAutoProxyCreator方法的实现
2.BeanClassTypeAutoProxyCreator需要有一个进行代理的ClassType列表,在bean进行初始化后就在context中查找类型为ClassType列表中类型的所有beanName.从而获得一个beanNames列表。
获得beanNames列表后就可以像BeanNameAutoProxyCreator一样实现自动代理了。
3.要想获得当前context,我们可以实现ApplicationContextAware接口。让BeanClassTypeAutoProxyCreator的bean可以获得当前context.
4. 要在bean进行初始化动作,可以实现InitializingBean接口,实现afterPropertiesSet,在这个方法中在context中根据classType查找获得相关的beanName的列表。
5. 写一个空接口,里面没有任何方法。需要事务代理的类实现这个空接口。
这样,只需要把这个空接口的全类名作为BeanClassTypeAutoProxyCreator的classTypes参数值,然后所有需要代理的类都去实现这个接口就可以自动获得代理了。无再需要任何配置。这样就可以让程序员专心于业务逻辑的开发,而无需要去关心事务控制方法,就像是没有使用事务一样。
完整的实现类如下:
BeanClassTypeAutoProxyCreator.java
/**
* 根据类型自动代理Creator
*
* @author yuanguangdong date: Jul 13, 2004
*/
public class BeanClassTypeAutoProxyCreator extends AbstractAutoProxyCreator
implements ApplicationContextAware, InitializingBean {
/** Logger that is available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
/** ApplicationContext this object runs in */
private ApplicationContext applicationContext;
/** MessageSourceAccessor for easy message access */
private MessageSourceAccessor messageSourceAccessor;
/**被代理的bean别名列表**/
private List beanNames;
/**被代理的classType列表**/
private List classTypes;
//---------------------------------------------------------
//实现AbstractAutoProxyCreator的抽像方法
//---------------------------------------------------------
/**
* @see org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getAdvicesAndAdvisorsForBean(java.lang.Class,
* java.lang.String, org.springframework.aop.TargetSource)
*/
protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass,
String beanName, TargetSource targetSource) throws BeansException {
if (this.beanNames != null) {
if (this.beanNames.contains(beanName)) {
return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
}
}
return DO_NOT_PROXY;
}
//-------------------------------------------------------
//实现ApplicationContextAware接口方法
//-------------------------------------------------------
/**
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
public void setApplicationContext(ApplicationContext context)
throws BeansException {
if (context == null && !isContextRequired()) {
// Reset internal context state.
this.applicationContext = null;
this.messageSourceAccessor = null;
} else if (this.applicationContext == null) {
// Initialize with passed-in context.
if (!requiredContextClass().isInstance(context)) {
throw new ApplicationContextException(
"Invalid application context: needs to be of type ["
+ requiredContextClass().getName() + "]");
}
this.applicationContext = context;
this.messageSourceAccessor = new MessageSourceAccessor(context);
initApplicationContext();
} else {
// Ignore reinitialization if same context passed in.
if (this.applicationContext != context) {
throw new ApplicationContextException(
"Cannot reinitialize with different application context: current one is ["
+ this.applicationContext
+ "], passed-in one is [" + context + "]");
}
}
}
/**
* Determine whether this application object needs to run in an
* ApplicationContext.
*
* Default is "false". Can be overridden to enforce running in a context
* (i.e. to throw IllegalStateException on accessors if outside a context).
*
* @see #getApplicationContext
* @see #getMessageSourceAccessor
*/
protected boolean isContextRequired() {
return true;
}
/**
* Determine the context class that any context passed to
* setApplicationContext must be an instance of. Can be
* overridden in subclasses.
*
* @see #setApplicationContext
*/
protected Class requiredContextClass() {
return ApplicationContext.class;
}
/**
* Return the ApplicationContext instance used by this object.
*/
public final ApplicationContext getApplicationContext()
throws IllegalStateException {
if (this.applicationContext == null && isContextRequired()) {
throw new IllegalStateException(
"ApplicationObjectSupport instance [" + this
+ "] does not run in an ApplicationContext");
}
return applicationContext;
}
/**
* Return a MessageSourceAccessor for the application context used by this
* object, for easy message access.
*
* @throws IllegalStateException
* if not running in an ApplicationContext
*/
protected final MessageSourceAccessor getMessageSourceAccessor()
throws IllegalStateException {
if (this.messageSourceAccessor == null && isContextRequired()) {
throw new IllegalStateException(
"ApplicationObjectSupport instance [" + this
+ "] does not run in an ApplicationContext");
}
return this.messageSourceAccessor;
}
public void setClassTypes(String[] classTypes) {
this.classTypes = Arrays.asList(classTypes);
}
/**
* Subclasses can override this for custom initialization behavior. Gets
* called by setApplicationContext after setting the context
* instance.
*
* Note: Does not get called on reinitialization of the context but
* rather just on first initialization of this object's context reference.
*
* @throws ApplicationContextException
* in case of initialization errors
* @throws BeansException
* if thrown by ApplicationContext methods
* @see #setApplicationContext
*/
protected void initApplicationContext() throws BeansException {
}
//-----------------------------------
//实现InitializingBean接口方法
//-----------------------------------
/**
* 查找指定classType的beanName列表
*/
private List getBeanNames(String classType) {
List beanNameList = null;
try {
String[] beanName = this.getApplicationContext()
.getBeanNamesForType(Class.forName(classType), true, false);
if (beanName != null) {
beanNameList = Arrays.asList(beanName);
}
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException("Class not found: "
+ ex.getMessage());
}
return beanNameList;
}
/**
*
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
if (classTypes != null && !classTypes.isEmpty()) {
beanNames = new ArrayList();
for (int i = 0; i < classTypes.size(); i++) {
String classType = (String) classTypes.get(i);
List aList = getBeanNames(classType);
beanNames.addAll(aList);
}
}
if (logger.isDebugEnabled()) {
for (int i = 0; i < beanNames.size(); i++) {
logger.debug("printBean:" + (String) beanNames.get(i));
}
}
}
}
3.使用BeanClassTypeAutoProxyCreator
3.1为了使用BeanClassTypeAutoProxyCreator,将为所有需要进行代理的类定一个接口。
package com.prs.application.ehld.biz.service;
public interface BaseService {
}
3.2 让需要代理的类实现或继承这个公共接口
package com.prs.application.ehld.sample.biz.service;
public interface SampleService extends BaseService {
public void setUserInfoDAO(UserInfoDAO userInfoDAO);
public void insertUserInfo(UserInfoDTO userInfo) throws BusinessServiceException;
}
3.3 配置事务代理
class="org.springframework.transaction.interceptor.TransactionInterceptor">
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
class="com.prs.application.ehld.common.aotoproxy.BeanClassTypeAutoProxyCreator">
transactionInterceptor
com.prs.application.ehld.biz.service.BaseService
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
效果:只需要定义BeanClassTypeAutoProxyCreator,把需要代理的类型BaseService作为classTypes的值。这样任何实现了BaseService接口的类都自动获得代理。使得程序员就像配置普通bean一样去配置一个需要事务代理的bean。使得程序员只需要去关心业务逻辑。而无需要去关注事务这些框架应该支持的事情。特别是当开发团队成员水平不一,或团队人员流动性大时,BeanClassTypeAutoProxyCreator就发挥了它的作用。一个好的架构设计应该对事务控制,异常处理,日志记录这些方面进行统一的规划和处理,才能保证系统的健壮性。
采用Spring框架进行项目开发,我们在获得它的IOC等好处,同时给我们增加了维护太多配置文件的负担。应该尽量减少bean的定义,更多采用嵌套bean定义。否则将加大项目后期的维护成本。作为一个架构设计者更是应该把通用性比较强的方面进行统一规划。
Spring颠覆了以前的编程模式,引入了IOC等全新的概念,广受大家的喜爱。目前大多数j2ee项目都已经采用Spring框架。Spring最大的问题是太多的配置文件,使得你不仅需要维护程序代码,还需要额外去维护相关的配置文件。最典型的就是事务配置(注:这里的“事务配置”都指“声明式事务配置”),在Spring中进行事务配置除了定义对象自身的bean外,还需要定义一个进行事务代理的bean.如果你有n个类需要引入事务,那么你就必须定义2n个bean。维护这些bean的代价是十分昂贵的,所以必须要对事务配置进行减化。如果你是基于Spring进行架构设计,那么作为一个好的架构设计师,应该把一些公共的方面进行简化,让项目的开发人员只关心项目的业务逻辑,而不要花费太多的精力去关心业务逻辑之外的太多东西。所以作为一个好的架构就应该把事务管理进行简化,让程序员花在编程之外的工作最小化。
1. Spring声明式事务配置的几种方法
在Spring中进行事务控制首先要选择适当的事务管理器,其次为程序选择划分事务的策略。如果只有单个事务性资源,可以从“单一资源”的PlatformTransactionManger实现当中选择一个,这些实现有:DataSourceTransactionManager,HibernateTransactionManager, JdoTransactionManager,PersistenceBrokerTransactionManager和JmsTransactionManager。根据你所采用的数据库持久化技术选择。如果你的项目运行于支持JTA的服务器,那么将选择JtaTransactionManger,将会支持多资源事务。
下表将为你选择适当的事务管理器提供参考。
技术 事务管理器 内建的事务支持
JDBC DataSurceTransactionManagerJtaTransactionManager JdbcTemplate和org.springframework.jdbc.object包中的所有类
IBATIS DataSourceTransactionManagerJtaTransactionManager SqlMapClientTemplate和SqlClientTemplate
Hibernate HibernateTransactionManagerJtaTransactionManager HibernateTemplate和HibernateInterceptor
JDO JdoTransactionManagerJtaTransactionManager JdoTemplate和JdoInterceptor
ApacheOJB PersistenceBrokerTransactionManagerJtaTransactionManager PersistenceBrokerTemplate
JMS JmsTransactionManager JmsTemplate
在划分事务时,我们需要进行事务定义,也就是配置事务的属性。事务的属性有传播行业,隔离级别,超时值及只读标志。TransactionAttribute接口指定哪些异常将导致一个回滚,哪些应该一次性提交。
(1) 使用ProxyFactoryBean 和TransactionInterceptor
class="org.springframework.transaction.interceptor.TransactionInterceptor">
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
ref="com.prs.application.ehld.sample.biz.service.sampleService.target">
transactionInterceptor
通过ProxyFacgtoryBean和TransactionInterceptor组合使用,可以对事务进行更多的控制。所有需要事务控制的对象可以共享一个transactionInterceptor的事务属性。
(2) 使用TransactionProxyFactoryBean
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
abstract="true">
ref="com.prs.application.ehld.sample.biz.service.sampleService.target" />
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
使用TransactionProxyFactoryBean需要为每一个代理对象都去定义自己的事务属性。
(3) 使用TransactionProxyFactoryBean及abstract属性来简化配置
这种方工也是目前使用得最多的一种声明式事务配置方法
abstract="true">
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
ref="com.prs.application.ehld.sample.biz.service.sampleService.target">
使用abstract属性,可以让代理对象可以共享一个定义好的事务属性,使配置简化。
(4)使用BeanNameAutoProxyCreator
class="org.springframework.transaction.interceptor.TransactionInterceptor">
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
transactionInterceptor
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
使用BeanNameAutoProxyCreator可以由框架来提供适当的代理,由一个transactionInterceptor统一定义事务属性,只需要把需要事务控制的bean加到beannames的列表。
对于需要大量声明式事务的bean,BeanNameAutoProxyCreator是十分方便的。减少了代理bean的定义,还可以灵活的决定一个bean是否进行事务控制。
上面四种方法是在Spring中常见的声明式事务配置方法,其中使用TransactionProxyFactoryBean及abstract属性进行配置是最常见的简化方法。
我们暂且把需要进行事务控制的bean叫事务bean.把依赖和调用它的bean叫做业务bean。对事务bean进行代理叫做事务代理bean.
1. 使用ProxyFactoryBean 和TransactionInterceptor,可以由一个TransactionInterceptor统一定义事务属性,对于每一个事务bean都需要再定义一个事务代理bean。如果有n个事务bean,那么就需要定义和维护2n个bean。并且注入到业务bean的不是事务bean本身,而是要求用事务代理bean注入。这增加了理解的难度。
2. 使用TransactionProxyFactoryBean需要为每一个事务代理bean都定义自己的事务属性,除了需要维护2n个bean外,还需要为每一个事务代理bean定义事务属性。可以说是最麻烦的。同样需要把事务代理bean注入到业务bean,增加了理解的难度和项目的复杂度。
3. 使用TransactionProxyFactoryBean及abstract属性是对使用TransactionProxyFactoryBean的一种简单化配置,可以让所有的事务bean共享一致的事务属性定义。需要维护2n个bean,需要把事务代理bean注入到业务bean。
4. 使用BeanNameAutoProxyCreator最适合在框架中使用,只需要维护n个bean。也无需要事务代理bean。直接把事务bean注入业务bean中。但是它必须把需要事务控制的bean加到beanNames列表中。
2.类型自动代理创建器BeanClassTypeAutoProxyCreator
得于BeanNameAutoProxyCreator的启示,BeanNameAutoProxyCreator可以实现框架来实现自动代理。它只是把需要代理的bean加入beanNames属性列表。大大的简化了代理的配置,减少了代理bean的定义,使用事务bean注入业务对象,而不是代理bean注入,更合乎事务逻辑。BeanNameAutoProxyCreator仍然需要开发人员除了定义业务bean外,还需要关心事务的定义,当然已经简单了很多。如果能实现一个BeanClassTypeAutoProxyCreator,为它指定一个可以代理的ClassType列表,那么在context中所有属于ClassType和其子类的bean都自动获得代理。
实现思路:
1.BeanNameAutoProxyCreator继承了AbstractAutoProxyCreator,去实现方法:
protected abstract Object[] getAdvicesAndAdvisorsForBean(
Class beanClass, String beanName, TargetSource customTargetSource)
在BeanNameAutoProxyCreator中的实现是判断beanName 是存在于beanNames列表,如果能找到则Object[]不对空。否则返回null。
所以BeanClassTypeAutoProxyCreator也应该继承AbstractAutoProxyCreator。
getAdvicesAndAdvisorsForBean方法的实现可以参照BeanNameAutoProxyCreator方法的实现
2.BeanClassTypeAutoProxyCreator需要有一个进行代理的ClassType列表,在bean进行初始化后就在context中查找类型为ClassType列表中类型的所有beanName.从而获得一个beanNames列表。
获得beanNames列表后就可以像BeanNameAutoProxyCreator一样实现自动代理了。
3.要想获得当前context,我们可以实现ApplicationContextAware接口。让BeanClassTypeAutoProxyCreator的bean可以获得当前context.
4. 要在bean进行初始化动作,可以实现InitializingBean接口,实现afterPropertiesSet,在这个方法中在context中根据classType查找获得相关的beanName的列表。
5. 写一个空接口,里面没有任何方法。需要事务代理的类实现这个空接口。
这样,只需要把这个空接口的全类名作为BeanClassTypeAutoProxyCreator的classTypes参数值,然后所有需要代理的类都去实现这个接口就可以自动获得代理了。无再需要任何配置。这样就可以让程序员专心于业务逻辑的开发,而无需要去关心事务控制方法,就像是没有使用事务一样。
完整的实现类如下:
BeanClassTypeAutoProxyCreator.java
/**
* 根据类型自动代理Creator
*
* @author yuanguangdong date: Jul 13, 2004
*/
public class BeanClassTypeAutoProxyCreator extends AbstractAutoProxyCreator
implements ApplicationContextAware, InitializingBean {
/** Logger that is available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
/** ApplicationContext this object runs in */
private ApplicationContext applicationContext;
/** MessageSourceAccessor for easy message access */
private MessageSourceAccessor messageSourceAccessor;
/**被代理的bean别名列表**/
private List beanNames;
/**被代理的classType列表**/
private List classTypes;
//---------------------------------------------------------
//实现AbstractAutoProxyCreator的抽像方法
//---------------------------------------------------------
/**
* @see org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator#getAdvicesAndAdvisorsForBean(java.lang.Class,
* java.lang.String, org.springframework.aop.TargetSource)
*/
protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass,
String beanName, TargetSource targetSource) throws BeansException {
if (this.beanNames != null) {
if (this.beanNames.contains(beanName)) {
return PROXY_WITHOUT_ADDITIONAL_INTERCEPTORS;
}
}
return DO_NOT_PROXY;
}
//-------------------------------------------------------
//实现ApplicationContextAware接口方法
//-------------------------------------------------------
/**
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
public void setApplicationContext(ApplicationContext context)
throws BeansException {
if (context == null && !isContextRequired()) {
// Reset internal context state.
this.applicationContext = null;
this.messageSourceAccessor = null;
} else if (this.applicationContext == null) {
// Initialize with passed-in context.
if (!requiredContextClass().isInstance(context)) {
throw new ApplicationContextException(
"Invalid application context: needs to be of type ["
+ requiredContextClass().getName() + "]");
}
this.applicationContext = context;
this.messageSourceAccessor = new MessageSourceAccessor(context);
initApplicationContext();
} else {
// Ignore reinitialization if same context passed in.
if (this.applicationContext != context) {
throw new ApplicationContextException(
"Cannot reinitialize with different application context: current one is ["
+ this.applicationContext
+ "], passed-in one is [" + context + "]");
}
}
}
/**
* Determine whether this application object needs to run in an
* ApplicationContext.
*
* Default is "false". Can be overridden to enforce running in a context
* (i.e. to throw IllegalStateException on accessors if outside a context).
*
* @see #getApplicationContext
* @see #getMessageSourceAccessor
*/
protected boolean isContextRequired() {
return true;
}
/**
* Determine the context class that any context passed to
* setApplicationContext must be an instance of. Can be
* overridden in subclasses.
*
* @see #setApplicationContext
*/
protected Class requiredContextClass() {
return ApplicationContext.class;
}
/**
* Return the ApplicationContext instance used by this object.
*/
public final ApplicationContext getApplicationContext()
throws IllegalStateException {
if (this.applicationContext == null && isContextRequired()) {
throw new IllegalStateException(
"ApplicationObjectSupport instance [" + this
+ "] does not run in an ApplicationContext");
}
return applicationContext;
}
/**
* Return a MessageSourceAccessor for the application context used by this
* object, for easy message access.
*
* @throws IllegalStateException
* if not running in an ApplicationContext
*/
protected final MessageSourceAccessor getMessageSourceAccessor()
throws IllegalStateException {
if (this.messageSourceAccessor == null && isContextRequired()) {
throw new IllegalStateException(
"ApplicationObjectSupport instance [" + this
+ "] does not run in an ApplicationContext");
}
return this.messageSourceAccessor;
}
public void setClassTypes(String[] classTypes) {
this.classTypes = Arrays.asList(classTypes);
}
/**
* Subclasses can override this for custom initialization behavior. Gets
* called by setApplicationContext after setting the context
* instance.
*
* Note: Does not get called on reinitialization of the context but
* rather just on first initialization of this object's context reference.
*
* @throws ApplicationContextException
* in case of initialization errors
* @throws BeansException
* if thrown by ApplicationContext methods
* @see #setApplicationContext
*/
protected void initApplicationContext() throws BeansException {
}
//-----------------------------------
//实现InitializingBean接口方法
//-----------------------------------
/**
* 查找指定classType的beanName列表
*/
private List getBeanNames(String classType) {
List beanNameList = null;
try {
String[] beanName = this.getApplicationContext()
.getBeanNamesForType(Class.forName(classType), true, false);
if (beanName != null) {
beanNameList = Arrays.asList(beanName);
}
} catch (ClassNotFoundException ex) {
throw new IllegalArgumentException("Class not found: "
+ ex.getMessage());
}
return beanNameList;
}
/**
*
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
public void afterPropertiesSet() throws Exception {
if (classTypes != null && !classTypes.isEmpty()) {
beanNames = new ArrayList();
for (int i = 0; i < classTypes.size(); i++) {
String classType = (String) classTypes.get(i);
List aList = getBeanNames(classType);
beanNames.addAll(aList);
}
}
if (logger.isDebugEnabled()) {
for (int i = 0; i < beanNames.size(); i++) {
logger.debug("printBean:" + (String) beanNames.get(i));
}
}
}
}
3.使用BeanClassTypeAutoProxyCreator
3.1为了使用BeanClassTypeAutoProxyCreator,将为所有需要进行代理的类定一个接口。
package com.prs.application.ehld.biz.service;
public interface BaseService {
}
3.2 让需要代理的类实现或继承这个公共接口
package com.prs.application.ehld.sample.biz.service;
public interface SampleService extends BaseService {
public void setUserInfoDAO(UserInfoDAO userInfoDAO);
public void insertUserInfo(UserInfoDTO userInfo) throws BusinessServiceException;
}
3.3 配置事务代理
class="org.springframework.transaction.interceptor.TransactionInterceptor">
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_REQUIRED
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
PROPAGATION_SUPPORTS,readOnly
class="com.prs.application.ehld.common.aotoproxy.BeanClassTypeAutoProxyCreator">
transactionInterceptor
com.prs.application.ehld.biz.service.BaseService
class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl">
ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO">
效果:只需要定义BeanClassTypeAutoProxyCreator,把需要代理的类型BaseService作为classTypes的值。这样任何实现了BaseService接口的类都自动获得代理。使得程序员就像配置普通bean一样去配置一个需要事务代理的bean。使得程序员只需要去关心业务逻辑。而无需要去关注事务这些框架应该支持的事情。特别是当开发团队成员水平不一,或团队人员流动性大时,BeanClassTypeAutoProxyCreator就发挥了它的作用。一个好的架构设计应该对事务控制,异常处理,日志记录这些方面进行统一的规划和处理,才能保证系统的健壮性。
采用Spring框架进行项目开发,我们在获得它的IOC等好处,同时给我们增加了维护太多配置文件的负担。应该尽量减少bean的定义,更多采用嵌套bean定义。否则将加大项目后期的维护成本。作为一个架构设计者更是应该把通用性比较强的方面进行统一规划。
发表评论
-
使用jstack分析cpu消耗过高的问题
2013-04-12 16:58 727http://www.iteye.com/topic/1114 ... -
jvm调试命令
2013-03-29 16:43 850http://hhhk.iteye.com/blog/1746 ... -
名词解释
2013-03-21 16:04 666ABA问题:http://www.iteye.com/prob ... -
nio reactor proactor(转)
2013-03-21 14:15 688两种I/O多路复用模式:Reactor和Proactor 一般 ... -
同步io,异步io,阻塞io,非阻塞io
2013-03-21 13:59 860按照《Unix网络编程》的划分,IO模型可以分为:阻塞IO、非 ... -
清华大学 老师 一席话 [转]
2011-02-18 18:04 6851、 一个人,如果你不 ... -
关于研发管理杂想
2010-07-27 23:32 793最近做开发的反思,感觉软件开发流程很随意,做一个东西不经过 ... -
java中synchronized用法
2010-05-28 16:33 941synchronized的一个简单例 ... -
转:class cannot be resolved to a type 或者JSP import class cannot be resolved to
2010-02-05 12:21 16859错误调试解析:class cannot be resolved ... -
一个小问题
2010-01-06 21:17 701不用jquery时很简单如下: var id="in ... -
synchronized 锁机制的经典解释
2009-09-28 15:50 858打个比方:一个object就像一个大房子,大门永远打开。房子里 ... -
虚拟主机为何不能直接用IP访问
2009-08-19 21:42 1705虚拟主机,顾名思义,是虚拟的主机,也就是说在一台服务器可以虚拟 ... -
动态代理推荐文章
2008-11-14 16:54 710http://blog.csdn.net/tyrone1979 ... -
Spring 的优秀工具类盘点
2008-11-06 16:13 769http://www.ibm.com/developerwor ... -
追MM与Java的23种设计模式
2008-10-07 14:29 778创建型模式 1 ... -
关于spring的 单实例问题
2008-05-30 13:44 1766以前一直没弄明白spring的bean是单实例的,在并发的情况 ... -
cas单点登陆配置心得--原创
2008-05-29 15:46 1799下午花了几个小时终于把yale的cas给搞定了,了却了一个 ... -
介绍一篇关于session的好文章,写的很详细--转
2008-05-28 09:32 1255目录: 一、术语session ... -
iBatis的JpetStore示例中MVC机制实现的研究--转
2008-04-19 23:12 1211JpetStore中的Action与普通Struts的Acti ... -
hibernate 需要导入的包--转
2008-02-21 16:15 2136hibernate2.jar: Hibernate的 ...
相关推荐
在实际项目中,开发者需要在web.xml中配置`SpringModuleFilter`和`SpringModuleInitListener`,确保Spring能够正确初始化并参与Struts的生命周期。同时,需要在Spring的配置文件中声明Struts相关的bean,如Action、...
这里提到的是一组完整的Spring库,包括`spring-core`、`spring-context`、`spring-webmvc`、`spring-web`、`spring-beans`、`spring-test`、`spring-jdbc`、`spring-orm`、`spring-aop`和`spring-tx`,它们都是3.2.0...
7. **消息支持**:Spring Integration和Spring AMQP提供了消息传递和事件驱动架构的支持,可与其他系统进行异步通信。 8. **云原生支持**:Spring Boot和Spring Cloud针对微服务和云环境进行了优化,简化了部署和...
Spring的AOP模块提供了在运行时对代码进行横切关注点(如日志、事务管理)的能力。它通过代理模式实现,可以将切面逻辑与业务代码分离,提高代码的复用性和模块化。 5. **设计模式** Spring框架广泛运用了多种...
Spring框架是Java开发中不可或缺的一部分,它以其模块化、易用性和灵活性著称。Spring-4.2.4是该框架的一个稳定版本,为开发者提供了丰富的功能和改进。在这个版本中,Spring团队继续致力于提高性能、增强可维护性和...
**Spring框架的示例项目源码 - Spring Petclinic** Spring Petclinic是Spring官方提供的一款开源示例应用,它用于展示Spring框架的各种特性及其在实际开发中的应用。该项目可以帮助开发者理解和学习Spring框架的...
Spring的模块化设计允许开发者根据项目需求选择必要的组件,避免不必要的复杂性。 描述中的"sts spring软件"进一步确认了这是一个与Spring框架密切相关的开发环境。Spring Tool Suite(STS)将Eclipse的强大学习...
通过这个插件,我们可以将Action类的实例化和管理交给Spring容器,从而实现更灵活的配置和更好的测试性。 接下来,Spring框架的核心组件之一是`spring-web-5.0.6.RELEASE.jar`,它是Spring MVC的实现,提供了处理...
《SPRING技术内幕:深入解析SPRING架构与设计原理》这本书深入探讨了Spring框架的核心机制和设计理念,旨在帮助读者理解并掌握Spring的精髓。Spring作为Java企业级应用开发的重要工具,其灵活性、可扩展性和模块化的...
`spring-beans-3.0.xsd` 文件定义了 Spring 容器如何读取并解析 XML 配置文件,来实例化、装配和管理 beans。在这个文件中,你可以定义 bean 的 id、class、属性、依赖注入等。通过版本号 3.0,我们可以看出这是针对...
本文将深入探讨基于Spring Cloud Eureka、Feign、MyBatis和Seata的分布式事务解决方案,帮助开发者理解如何在微服务架构中实现高效、可靠的事务管理。 首先,Spring Cloud Eureka是Netflix公司提供的一个服务注册与...
`LocalSessionFactoryBean`是一个Spring的bean,负责配置和初始化Hibernate的`SessionFactory`。开发者可以通过它来配置Hibernate的属性,如数据库连接信息、实体映射文件等,从而在Spring应用中使用Hibernate进行...
- **Spring Boot**:虽然不在4.2.4.RELEASE中,但作为Spring的现代分支,它简化了应用的初始化和配置,是现代Spring应用开发的首选方式。 此外,Spring还支持MVC、RESTful服务、WebSocket、任务调度、邮件服务等...
《Spring技术内幕:深入解析Spring架构与设计原理(第2版)》这本书主要聚焦于Spring框架的核心架构和技术细节,帮助读者全面理解Spring的工作机制、设计理念以及实现方式。下面将根据书名及其描述来展开相关知识点。 ...
作为Spring框架的专用IDE,STS是Eclipse的定制版本,它包含了丰富的Spring插件和工具,如Spring Roo、Spring Insight、Spring Beans图形视图等,这些工具能够简化Spring项目的创建、配置和调试过程,提高开发效率。...
- **微服务架构**:Spring Cloud为分布式系统提供了一整套解决方案,如服务发现、配置中心、熔断机制等。 - **数据访问**:通过Spring Data JPA,可以方便地实现数据库操作,支持复杂查询和事务控制。 - **Web应用**...
首先,Spring Framework 1.2.7 是Spring早期的一个稳定版本,它包含了对Java EE 5的初步支持,提供了一种模块化的架构,使得开发者可以按需选择使用哪些模块。这一版本的核心特性包括: 1. **依赖注入(Dependency ...
5. **MVC(Model-View-Controller)模块**:Spring MVC是Spring框架的一部分,提供了一种用于构建Web应用的模型-视图-控制器架构。 6. **Test模块**:提供了对JUnit和TestNG的支持,方便进行单元测试和集成测试。 ...
Spring Boot则进一步简化了Spring应用的初始化和配置,通过预设的默认值和自动配置功能,使开发者能够快速搭建新项目。 在Spring Framework 4.3.18.RELEASE中,开发者还可以利用Spring Security进行身份验证和授权...
Spring Boot简化了Spring应用程序的启动和配置,而Spring Cloud则为微服务架构提供了工具和服务发现、配置中心、负载均衡等功能。 Spring Framework 5.3.23版本的更新可能包括性能提升、新的API和改进的兼容性。...