spring aop 使用 cglib 引起的空指针 NullPointerException
问题
产生空指针的代码如下:
HibernateDaoSupport.java
代码如下:
public abstract class HibernateDaoSupport extends DaoSupport { private HibernateTemplate hibernateTemplate; public final void setSessionFactory(SessionFactory sessionFactory) { if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) { this.hibernateTemplate = createHibernateTemplate(sessionFactory); } } public final SessionFactory getSessionFactory() { return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null); } }
BaseDao.java
代码如下:
@Repository public class BaseDao<T> extends HibernateDaoSupport { @Resource(name="sessionFactory") public void setSuperSessionFactory(SessionFactory sessionFactory){ super.setSessionFactory(sessionFactory); } ....... }
CategoriesDao.java
代码如下:
public class CategoriesDao extends BaseDao<Categories>{ }
配置文件内容如下:
<aop:config> <aop:aspect id="dataSourceAspect" ref="dataSourceRouterAspect"> <aop:before method="before" pointcut="execution(* com.litb.v3.center.database.auto.dao.CategoriesDao.*(..))"/> </aop:aspect> </aop:config>
使用 aop 对 CategoriesDao
增强。
BusinessService.java
代码如下:
public class BusinessService { @Autowired private CategoriesDao categoriesDao; private void bindSession(){ SessionFactory sessionFactory = categoriesDao.getSessionFactory(); // 上面代码获取的 SessionFactory 为 null if (TransactionSynchronizationManager.hasResource(sessionFactory)) { } else { ...... } } }
上面的代码,执行 bindSession()
方法时,获取的 sessionFactory
为 null。
排查
在 bindSession()
方法中打断点,查看 sessionFactory
变量。如下图:
从上图中可以看出,spring 是使用 cglib 进行的增强。CategoriesDao 的实例是 cglib 生成的一个代理类。代理类中 Interceptor
里实际保存了原始的 target
对象。target
对象中的 hibernateTemplate
变量不为 null。而代理类的 hibernateTemplate
变量为 null。
cglib 是通过动态生成子类来实现代理的。代理类中会调用 target
对象中相应的方法。cglib 是没有办法对 final
修饰的方法进行代理的。 因此,在调用 getSessionFactory()
方法时,方法中的 this.hibernateTemplate
是指代理类实例的成员变量,而不是 target
对象的相应成员变量。因此,返回值是 null。
解决
既然 cglib 对 final
关键字修饰的方法没有办法进行代理。那我们就在 BaseDao
新增一个非 final
修饰的方法。增加的方法代码如下:
public SessionFactory getCurrentSessionFactory() { return this.getSessionFactory(); }
然后,把 categoriesDao.getSessionFactory();
改为 categoriesDao.getCurrentSessionFactory();
;
扩展
* dumpclass分析 https://github.com/exinnet/dumpclass
参考
https://blog.csdn.net/hengyunabc/article/details/78806296
https://stackoverflow.com/questions/11580911/spring-singleton-bean-fields-are-not-populated
https://my.oschina.net/shishuifox/blog/122455
技术交流
原文链接:spring aop 使用 cglib 引起的空指针 NullPointerException,转载请注明来源!
非常好