- 浏览: 53724 次
- 性别:
- 来自: 深圳
文章分类
最新评论
-
nevergiveup3:
学习啦!讲的很细。
struts+hibernate+spring (整合使用) -
抛出异常的爱:
请排版....把代码用代码框框起来.
struts+hibernate+spring (整合使用) -
apojava:
我现在正在学习SSH,看了以后收获不小.
谢谢了!
struts+hibernate+spring (整合使用) -
williamy:
刚学java?
struts+hibernate+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
<!--定义本地数据源-->
通过ProxyFacgtoryBean和TransactionInterceptor组合使用,可以对事务进行更多的控制。所有需要事务控制的对象可以共享一个transactionInterceptor的事务属性。
(2) 使用TransactionProxyFactoryBean
使用TransactionProxyFactoryBean需要为每一个代理对象都去定义自己的事务属性。
(3) 使用TransactionProxyFactoryBean及abstract属性来简化配置
这种方工也是目前使用得最多的一种声明式事务配置方法
使用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.
* <p>
* 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
* <code>setApplicationContext</code> 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 <code>setApplicationContext</code> after setting the context
* instance.
* <p>
* Note: Does </i>not</i> 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 配置事务代理
效果:只需要定义BeanClassTypeAutoProxyCreator,把需要代理的类型BaseService作为classTypes 的值。这样任何实现了BaseService接口的类都自动获得代理。使得程序员就像配置普通bean一样去配置一个需要事务代理的bean。使得程序员只需要去关心业务逻辑。而无需要去关注事务这些框架应该支持的事情。特别是当开发团队成员水平不一,或团队人员流动性大时, BeanClassTypeAutoProxyCreator就发挥了它的作用。一个好的架构设计应该对事务控制,异常处理,日志记录这些方面进行统一的规划和处理,才能保证系统的健壮性。
采用Spring框架进行项目开发,我们在获得它的IOC等好处,同时给我们增加了维护太多配置文件的负担。应该尽量减少bean的定义,更多采用嵌套bean定义。否则将加大项目后期的维护成本。作为一个架构设计者更是应该把通用性比较强的方面进行统一规划。
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
<!--定义本地数据源-->
<bean id="dataSource" name="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="${jdbc.driverClassName}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- !定义单个jdbc数据源的事务管理器--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!—定义拦截器--> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> </props> </property> </bean> <!—定义业务对象--> <bean id="com.prs.application.ehld.sample.biz.service.sampleService.target" class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl"> <property name="userInfoDAO" ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO"> </property> </bean> <!—定义业务对象的事务代理对象--> <bean id="com.prs.application.ehld.sample.biz.service.sampleService" class="org.springframeword.aop.framework.ProxyFacgtoryBean"> <property name="target" ref="com.prs.application.ehld.sample.biz.service.sampleService.target"> </property> <property name="interceptorNames"> <value>transactionInterceptor</value> </property> </bean>
通过ProxyFacgtoryBean和TransactionInterceptor组合使用,可以对事务进行更多的控制。所有需要事务控制的对象可以共享一个transactionInterceptor的事务属性。
(2) 使用TransactionProxyFactoryBean
<!—定义业务对象--> <bean id="com.prs.application.ehld.sample.biz.service.sampleService.target" class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl"> <property name="userInfoDAO" ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO"> </property> </bean> <!—定义业务对象的事务代理对象--> <bean id="com.prs.application.ehld.sample.biz.service.sampleService" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="target" ref="com.prs.application.ehld.sample.biz.service.sampleService.target" /> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> </props> </property> </bean>
使用TransactionProxyFactoryBean需要为每一个代理对象都去定义自己的事务属性。
(3) 使用TransactionProxyFactoryBean及abstract属性来简化配置
这种方工也是目前使用得最多的一种声明式事务配置方法
<!--事务控制代理抽象定义 --> <bean id="baseTransactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> </props> </property> </bean> <!—定义业务对象--> <bean id="com.prs.application.ehld.sample.biz.service.sampleService.target" class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl"> <property name="userInfoDAO" ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO"> </property> </bean> <!—定义业务对象的事务代理对象--> <bean id="com.prs.application.ehld.sample.biz.service.sampleService" parent="baseTransactionProxy"> <property name="target" ref="com.prs.application.ehld.sample.biz.service.sampleService.target"> </property> </bean> 使用abstract属性,可以让代理对象可以共享一个定义好的事务属性,使配置简化。 (4)使用BeanNameAutoProxyCreator <!—定义拦截器--> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> </props> </property> </bean> <!—定义bean别名自动代理创建器--> <bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"> <property name="interceptorNames"> <value>transactionInterceptor</value> </property> <property name="beanNames"> <list> <idref local="com.prs.application.ehld.sample.biz.service.sampleService"/> </list> </property> </bean> <!—定义业务对象--> <bean id="com.prs.application.ehld.sample.biz.service.sampleService" class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl"> <property name="userInfoDAO" ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO"> </property> </bean>
使用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.
* <p>
* 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
* <code>setApplicationContext</code> 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 <code>setApplicationContext</code> after setting the context
* instance.
* <p>
* Note: Does </i>not</i> 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 配置事务代理
<!—定义拦截器--> <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor.TransactionInterceptor"> <property name="transactionManager"> <ref bean="transactionManager"/> </property> <property name="transactionAttributes"> <props> <prop key="insert*">PROPAGATION_REQUIRED</prop> <prop key="update*">PROPAGATION_REQUIRED</prop> <prop key="save*">PROPAGATION_REQUIRED</prop> <prop key="find*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop> <prop key="*">PROPAGATION_SUPPORTS,readOnly</prop> </props> </property> </bean> <!—定义类型自动代理创建器--> <bean id="autoClassTypeProxyCreator" class="com.prs.application.ehld.common.aotoproxy.BeanClassTypeAutoProxyCreator"> <property name="interceptorNames"> <value>transactionInterceptor</value> </property> <property name="classTypes"> <list> <value>com.prs.application.ehld.biz.service.BaseService</value> </list> </property> </bean> <!—定义事务bean--> <bean id="com.prs.application.ehld.sample.biz.service.sampleService" class="com.prs.application.ehld.sample.biz.service.impl.SampleServiceImpl"> <property name="userInfoDAO" ref="com.prs.application.ehld.sample.integration.dao.userInfoDAO"> </property> </bean>
效果:只需要定义BeanClassTypeAutoProxyCreator,把需要代理的类型BaseService作为classTypes 的值。这样任何实现了BaseService接口的类都自动获得代理。使得程序员就像配置普通bean一样去配置一个需要事务代理的bean。使得程序员只需要去关心业务逻辑。而无需要去关注事务这些框架应该支持的事情。特别是当开发团队成员水平不一,或团队人员流动性大时, BeanClassTypeAutoProxyCreator就发挥了它的作用。一个好的架构设计应该对事务控制,异常处理,日志记录这些方面进行统一的规划和处理,才能保证系统的健壮性。
采用Spring框架进行项目开发,我们在获得它的IOC等好处,同时给我们增加了维护太多配置文件的负担。应该尽量减少bean的定义,更多采用嵌套bean定义。否则将加大项目后期的维护成本。作为一个架构设计者更是应该把通用性比较强的方面进行统一规划。
相关推荐
Java SSM项目是一种使用Java语言和SSM框架(Spring + Spring MVC + ...它提供了一种将数据库操作与Java对象映射起来的方式,避免了手动编写繁琐的SQL语句,并提供了事务管理和缓存等功能,简化了数据库访问的过程
- chapter9-1-4:[Spring Cloud构建微服务架构(四)分布式配置中心](http://blog.didispace.com/springcloud4/) - chapter9-1-5:[Spring Cloud构建微服务架构(五)服务网关]...
2.8 用Java Config简化XML配置 77 2.8.1 问题 77 2.8.2 解决方案 77 2.8.3 工作原理 77 2.9 使Bean感知容器 81 2.9.1 问题 81 2.9.2 解决方案 81 2.9.3 工作原理 82 2.10 加载外部资源 82 2.10.1...
JavaSpring的商城项目 Java Spring是一个开源的Java...事务管理:Spring提供了一致的事务管理接口,可以在JTA(Java Transaction API)或非托管环境中使用,简化了事务管理代码。 模型-视图-控制器(MVC):Spring的W
│ 12 配置中心:基于 Naco 集中管理应用配置.mp4 │ 15 应用性能监控:通过 SkyWalking 实施链路追踪.mp4 │ 16 分布式事务:Alibaba Seata 如何实现分布式事务.mp4 │ 17 消息队列:基于 RocketMQ 实现服务...
它里面包含了Spring,SpringMVC,SpringData(事务),SrpingTest等等。 其中: Spring本身里面包含了两大核心IOC和AOP。IOC负责降低我们代码间的依赖关系,使我们的项目灵活度更高,可复用性更强。AOP是让方法间...
2.8 用Java Config简化XML配置 77 2.8.1 问题 77 2.8.2 解决方案 77 2.8.3 工作原理 77 2.9 使Bean感知容器 81 2.9.1 问题 81 2.9.2 解决方案 81 2.9.3 工作原理 82 2.10 加载外部资源 82 2.10.1...
模块化管理:通过整合,可以将MyBatis作为Spring应用程序架构的一部分进行管理和组织。可以使用Spring的IoC容器来管理MyBatis的会话工厂、数据源和其他相关的对象,使整个应用程序更易于维护和扩展。 增加开发效率...
Spring 框架是一个分层架构,由 7 个定义良好的模块组成。Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式,如图 1 所示。 组成 Spring 框架的每个模块(或组件)都可以单独存在,或者...
Hibernate则是一种对象关系映射(ORM)工具,它可以让开发者用面向对象的方式来操作数据库,极大地简化了数据访问层的编码工作。而Spring框架则提供了一系列的企业级服务,如事务管理、依赖注入等,使得整个系统更加...
该资料包采用了Struts框架来管理Web层的请求与响应,Hibernate作为对象关系映射(ORM)工具以简化数据库操作,并通过Spring框架实现依赖注入和业务逻辑管理,确保了系统架构的健壮性和灵活性。该系统旨在提供一个...
Spring架构上的好处 在我们进入细节之前,让我们来看看Spring能够给工程带来的种种好处: Spring能有效地组织你的中间层对象,不管你是否选择使用了EJB。如果你仅仅使用了Struts或其他为J2EE的 API特制的...
这是一个基于MVC架构的高校办公室行政事务管理系统,使用Java语言开发,采用Spring Boot框架和MySQL数据库。该系统主要用于帮助高校办公室管理人员高效地处理各类行政事务,提高工作效率。系统主要功能如下:用户...
包括缓存(一二级缓存,自动缓存管理),粒度,分布式定时任务,文件服务(七牛,阿里云OSS,fastDFS),日志,搜索,代码生成,API网关,配置中心,统一认证平台,分布式锁,分布式事务,集成dubbo,spring boot...
1. **Spring**: Spring是一个开源的轻量级应用程序框架,提供了全面的编程和配置模型。它的核心特性是依赖注入(DI)和面向切面编程(AOP),这些特性让开发人员能够编写松耦合、易于测试的代码。Spring还提供了一...
11.3.3简化配置 233 11.4理解spring的核心——ioc 234 11.4.1控制反转 234 11.4.2依赖注入的3种方式 236 11.5beanfactory与applicationcontext 238 11.5.1认识beanfactory 238 11.5.2使用applicationcontext ...
此外,Spring还提供了一套丰富的注解,用于简化常见的开发任务,如事务管理、数据访问等。其次,Spring MVC框架负责处理Web应用程序的请求和响应。它提供了一种简洁的方式来定义MVC架构中的模型-视图-控制器(Model-...
Spring Boot的自动配置特性大大简化了项目的配置过程,使得开发者能够快速启动和运行应用。模块化设计:系统被划分为多个模块,如用户管理、公文流转、项目管理、财务管理等,每个模块都可以独立开发、测试和部署,...
整个系统以Spring Boot为基础,简化了传统Spring应用的复杂配置和管理,同时继承了Spring生态系统的强大功能。这款医院核酸检测服务系统不仅提供了一个全面的核酸检测服务和管理平台,还通过智能化服务和数据支持,...