spring aop 使用 cglib 引起的空指標 NullPointerException
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
原文連結:ofollow,noindex" target="_blank">spring aop 使用 cglib 引起的空指標 NullPointerException ,轉載請註明來源!