Fist of all happy new year! Some work has been doing on Spring 3 and Ibatis 3 integration.
Having a look at mappers internals we saw that a new MapperMethod is created (with some introspection work) on each call to a mapper method. I wonder if it would be better to build them all during startup or maybe cache them somehow. this is the Jira issue (http://jira.springframework.org/browse/SPR-5991) Grabriel Axel posted it here some months ago (he opened the issue) The main problem with this task is that MapperMethods are not thread safe and that they hold an SqlSession. Enabling cache would require to make some changes to MapperMethods. SqlSession should be passed as an argument to execute instead to its constructor. public MapperMethod(Method method, Configuration configuration) { paramNames = new ArrayList<String>(); paramPositions = new ArrayList<Integer>(); ... public Object execute(Object[] args, SqlSession sqlSession) { Object result; if (SqlCommandType.INSERT == type) { ... And MapperProxy public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return new MapperMethod(method, sqlSession.getConfiguration()).execute(args, sqlSession); } So for example Spring could have this code to use directly injected Mappers where SqlSession is got from spring's transaction context. private Map<Method, MapperMethod> mapperMethods = new ConcurrentHashMap<Method, MapperMethod>(); public <T> T getMapper(final Class<T> type) { // mimic iBATIS MapperProxy return (T) java.lang.reflect.Proxy.newProxyInstance(type.getClassLoader(), new Class[] { type }, new InvocationHandler() { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { return execute(new SqlSessionCallback<T>() { @Override public T doInSqlSession(SqlSession sqlSession) throws SQLException { // mimic iBATIS MapperProxy Class<?> type = method.getDeclaringClass(); if (!sqlSession.getConfiguration().hasMapper(type)) { throw new BindingException("Type " + type + " is not known to the MapperRegistry."); } MapperMethod mm = mapperMethods.get(method); if (mm == null) { mm = new MapperMethod(method, sqlSession.getConfiguration()); mapperMethods.put(method, mm); } else { logger.debug("Returning a cached mapper method"); } return (T) mm.execute(args, sqlSession); } }); } }); } Or maybe avoid using directly MapperMethods and access to them thought the "standard" api SqlSession.getConfiguration().getMapper(impl, sesion) but in that case caching should be done inside. what do you think about this?