首页 » 编程语言 » Java » spring aop 使用 cglib 引起的空指针 NullPointerException

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 变量。如下图:
cglib

从上图中可以看出,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,转载请注明来源!

原文链接:spring aop 使用 cglib 引起的空指针 NullPointerException,转载请注明来源!

3