spring使用事务管理时的问题

1 InputStream is = new FileInputStream("Hibernate-Context.xml");
2 XmlBeanFactory factory = new XmlBeanFactory(is);
3 IUserDAO userDAO = (IUserDAO)factory.getBean("userDAOProxy");
4 User user = new User();
5 user.setUsername("erica");
6 user.setPassword("mypass");
7 userDAO.insertUser(user);

     这段代码似乎并没有什么特殊,但有一个细微之处:IUserDAO userDAO = (IUserDAO)factory.getBean("userDAOProxy");
     这里并没有直接用UserDAO对获得的Bean实例进行强制转型。这与上面JdbcTemplate的测试代码不同。并非完全出自设计上的考虑,这里情况有些特殊,我们可以尝试一下用UserDAO类对bean实例进行强制转型,不过将得到一个ClassCastException,程序异常中止。

     为什么会出现这样的问题?是不是只有在使用Hibernate才会出现这样的问题?事实并非如此,如果对上面基于JdbcTempate的UserDAO进行改造,使之实现IUserDAO接口,
同样的问题也将会出现。IUserDAO接口本身非常简单(仅包含一个insertUser方法的定义),显然也不是导致异常的原因所在。原因在于Spring的AOP实现机制,前面曾经提及,Spring中的事务管理实际上是基于动态AOP机制实现,为了实现动态AOP,Spring在默认情况下会使用Java Dynamic Proxy,但是,Dynamic Proxy要求其代理的对象必须实现一个接口,该接口定义了准备进行代理的方法。而对于没有实现任何接口的Java Class,需要采用其他方式,Spring通过CGLib10实现这一功能。

      当UserDAO没有实现任何接口时(如JdbcTemplate示例中)。Spring通过CGLib对UserDAO进行代理,此时getBean返回的是一个继承自UserDAO类的子类实例,可以通过UserDAO对其强制转型。而当UserDAO实现了IUserDAO接口之后,Spring将通过Java Dynamic Proxy机制实现代理功能,此时返回的Bean,是通过java.lang.reflect.Proxy.newProxyInstance方法创建的IUserDAO接口的一个代理实现,这个实例实现了IUserDAO接口,但与UserDAO类已经没有继承关系,因此无法通过UserDAO强制转型。

      由于此问题牵涉到较为底层的代理机制实现原理,下面的AOP章节中我们再进行详细探讨。实际开发中,应该面向接口编程,通过接口来调用Bean提供的服务。

posted @ 2012-08-21 17:54  lanse_yan  阅读(202)  评论(0编辑  收藏  举报