基于注解的Spring AOP拦截含有泛型的DAO
- 出错场景
1、抽象类BaseDao
public abstract class BaseDao<T> {
public BaseDao() {
entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
}
private Class<T> entityClass;
@Resource
private SessionFactory sessionFactory;
}
2、applicationContext.xml文件中配置:需要引入aop的命名空间和增加如下配置
<aop:aspectj-autoproxy proxy-target-class="true"/>
3、编写自己的aop类
@Component
@Aspect
public class GlobalValueAspect {
@Pointcut(
"execution(* com.test.dao.SceneryDao.save*(..)) " +
"|| execution(* com.test.dao.SceneryDao.update*(..)) " +
"|| execution(* com.test.dao.SceneryDao.delete*(..))")
public void aspect(){}
@Before("aspect()")
public void before(JoinPoint joinPoint){
System.out.println("before");
}
@After("aspect()")
public void after(JoinPoint joinPoint){
System.out.println("after");
}
@Around("aspect()")
public void around(JoinPoint joinPoint){
System.out.println("around");
}
@AfterThrowing("aspect()")
public void afterThrowing(){
System.out.println("afterthrow");
}
@AfterReturning("aspect()")
public void afterReturn(JoinPoint joinPoint){
}
@Resource
private GlobalValueAspectDao globalValueAspectDao;
}
4、运行时会报一个错误
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sceneryDao' defined in file : Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.lztravel.dao.SceneryDao]: Common causes of this problem include using a final class or a non-visible class; nested exception is org.springframework.cglib.core.CodeGenerationException: java.lang.ClassCastException-->java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:529)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4206)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4705)
at org.apache.catalina.core.StandardContext.reload(StandardContext.java:3461)
at org.apache.catalina.loader.WebappLoader.backgroundProcess(WebappLoader.java:426)
at org.apache.catalina.core.ContainerBase.backgroundProcess(ContainerBase.java:1361)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1653)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1662)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.processChildren(ContainerBase.java:1662)
at org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor.run(ContainerBase.java:1642)
at java.lang.Thread.run(Unknown Source)
Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class : Common causes of this problem include using a final class or a non-visible class; nested exception is org.springframework.cglib.core.CodeGenerationException: java.lang.ClassCastException-->java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:211)
at org.springframework.aop.framework.ProxyFactory.getProxy(ProxyFactory.java:111)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.createProxy(AbstractAutoProxyCreator.java:477)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:362)
at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:322)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:409)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1488)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
... 21 more
Caused by: org.springframework.cglib.core.CodeGenerationException: java.lang.ClassCastException-->java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
at org.springframework.cglib.core.ReflectUtils.newInstance(ReflectUtils.java:235)
at org.springframework.cglib.core.ReflectUtils.newInstance(ReflectUtils.java:220)
at org.springframework.cglib.core.ReflectUtils.newInstance(ReflectUtils.java:216)
at org.springframework.cglib.proxy.Enhancer.createUsingReflection(Enhancer.java:643)
at org.springframework.cglib.proxy.Enhancer.firstInstance(Enhancer.java:538)
at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:225)
at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:377)
at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:285)
at org.springframework.aop.framework.CglibAopProxy.getProxy(CglibAopProxy.java:205)
... 28 more
Caused by: java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
at com.test.dao.BaseDao.<init>(BaseDao.java:23)
at com.test.dao.SceneryDao.<init>(SceneryDao.java:13)
- 原因分析
Spring AOP是通过代理实现的,代理类继承了这里的SceneryDao,而SceneryDao继承了抽象类BaseDao,所以对于aop代理类来说,执行BaseDao中下面这句代码时出错了。
entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
因为代理类的父类是SceneryDao,而SceneryDao不是一个泛型类型(ParameterizedType),所以出现强制类型转换错误。
- 解决方法:
在BaseDao的构造方法中增加一个判断语句:if (getClass().getGenericSuperclass() instanceof ParameterizedType)。具体修改构造方法如下:
public BaseDao() {
if (getClass().getGenericSuperclass() instanceof ParameterizedType) {
entityClass = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
} else {
entityClass = (Class<T>) ((ParameterizedType) getClass().getSuperclass().getGenericSuperclass())
.getActualTypeArguments()[0];
}
}