- <bean id="transactionManager"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />.....
- lt;/bean>
- <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
- <property name="dataSource" ref="dataSource" />
- .....
- lt;/bean>
- <span style="font-size:18px">public interface DataSource extends CommonDataSource,Wrapper {
- /**
- * <p>Attempts to establish a connection with the data source that
- * this <code>DataSource</code> object represents.
- *
- * @return a connection to the data source
- * @exception SQLException if a database access error occurs
- */
- Connection getConnection() throws SQLException;
- /**
- * <p>Attempts to establish a connection with the data source that
- * this <code>DataSource</code> object represents.
- *
- * @param username the database user on whose behalf the connection is
- * being made
- * @param password the user's password
- * @return a connection to the data source
- * @exception SQLException if a database access error occurs
- * @since 1.4
- */
- Connection getConnection(String username, String password)
- throws SQLException;</span><span style="font-size:18px">
- </span>
这两个方法均是获取Connection对象的。Spring有没有可能对这个接口创建一个代理呢?通过spring的AOP。然后偷偷将Spring容器里面的datasource的bean指向这个代理对象(此处称该对象为datasourceproxy,替换之前的叫datasource)。于是不管是从哪里调用Datasource,那必然会被Spring拦截。下面是模拟了一个简单实现:
- public class DatasourceHandler implements InvocationHandler {
- private DataSource dataSource;
- /**
- * @param dataSource
- */
- public DatasourceHandler(DataSource dataSource) {
- super();
- this.dataSource = dataSource;
- }
- /* (non-Javadoc)
- * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
- */
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- if(method.getName().equals("getConnection")){
- if(ResourceHolder.getResource(proxy)!=null){
- Connection connection = (Connection) method.invoke(this.dataSource, args);
- ResourceHolder.addResource(proxy, connection);
- }
- return ResourceHolder.getResource(proxy);
- }else{
- return method.invoke(this.dataSource, args);
- }
- }
- }
上面这个类是一个InvocationHandler的实现,假设这个就是Spring Aop拦截Datasource的实现。那么这个对象里面有一个datasource对象,这个对象是Spring替换代理Datasource之前的那个对象(datasource)。看到invoke的实现,其实就是将代理(datasourceproxy)调用的类发转到datasource去调用,其实还是调用了datasource,但是这里就加入了一些特殊的东西,那就是ResourceHolder
- <span style="font-size:18px">public class ResourceHolder {
- private static ThreadLocal<Map<Object,Object>> resources= new ThreadLocal<Map<Object,Object>>();
- public static void addResource(Object key,Object value){
- if(resources.get()==null){
- resources.set(new HashMap<Object,Object>());
- }
- resources.get().put(key, value);
- }
- public static Object getResource(Object key){
- return resources.get().get(key);
- }
- public static void clear(){
- resources.remove();
- }
- }</span>
Connection connection =(Connection) method.invoke(this.dataSource, args);
ResourceHolder.addResource(proxy, connection);
}
其中proxy就是Spring自动生成的datasourceproxy,将proxy和connection的关系添加到ResourceHolder里面去,而ResourceHolder又是将这个关系添加到ThreadLocal<Map<Object,Object>> resources这个静态变量里面,添加到这个里面,那么以后如果在当前线程从datasourceproxy获取connection对象,都将是一个对象,这就保证了一个业务方法里面进行多次dao操作,调用的都是一个connection对象,同时保证了多个dao都是在一个事务里面。既然这样,那么Spring的事务管理就可以在调用业务方法之前,先从datasource里面先获得一个connection对象,并且对connection添加上用户配置的事务规则,由于这个connection对象会自动添加到ThreadLocal里面,那么后面的业务处理方法将会是调用已经添加好事务规则的connection对象,当业务方法处理完毕,那么spring事务就可以对这个connection进行回滚或者提交了。经过这样一个过程,那么在一个处理某个业务的线程里面执行流程应该是这样的:
403



被折叠的 条评论
为什么被折叠?



