lsn丶 2016-07-07 07:22 采纳率: 0%
浏览 5441
已结题

Sping AOP 无法拦截父类方法的问题

各位好,我在项目中尝试使用SpringAOP拦截子类调用父类的方法,发现AOP无法切入到父类中,困惑许久,在网上寻了各种方法都没有解决,希望各位同行可以帮我指出其中的问题,不胜感激。

子类:

 @Repository("userLoginDao")
public class UserLoginDaoImpl  extends BaseDao<UserLogin> implements IUserLoginDao{

    @Override
    public UserLogin addUserlogin(UserLogin userLogin) {
        insertSelective(userLogin);
        return userLogin;
    }
}

** 父类: **


public  class BaseDao<E> extends SqlSessionDaoSupport  {

    protected String daoName;
    private SqlSessionTemplate sqlSessionTemplate = null;

    @Autowired
    protected void setSessionTemplate(SqlSessionTemplate sessionTemplate) {
        super.setSqlSessionTemplate(sessionTemplate);
        this.sqlSessionTemplate = sessionTemplate;
    }

    @SuppressWarnings("unchecked")
    @PostConstruct
    protected void init() {
        ParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
        Class<E> daoType = (Class<E>) parameterizedType.getActualTypeArguments()[0];
        this.daoName = "mapper."+ daoType.getName().substring(daoType.getName().lastIndexOf(".") + 1) + "Mapper.";
    }

    @InsertLog(description="添加")
    public int insertSelective(E bean) {
        return this.getSqlSession().insert(this.daoName + "insertSelective", bean);
    }
}

** AOP拦截器:**

@Aspect
@Order(90)
@Component
public class ServiceLogAspect {
    private ThreadLocal<Map<String, Object>> serviceLocalMap = new ThreadLocal<Map<String, Object>>();

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    //使用标签和匹配都试过不可以
    // @Pointcut("@annotation(com.company.project.core.aoplog.InsertLog)")
    @Pointcut("execution(* com.company.project.service.user.base.BaseDao.insert*(..))")
    public void insertDaoAspect() {
    }

    // ----------------------------------对增加方法sql的记录
    @Around("insertDaoAspect()")
    public Object insertDaoAspect(final ProceedingJoinPoint pjp) throws Throwable {
        Map<String, Object> map = serviceLocalMap.get();
        // 获取操作的实体的类名
        String modelName = null;
        Field fields[] = pjp.getTarget().getClass().getDeclaredFields();// 获得对象所有属性
        for (Field field : fields) {
            field.setAccessible(true);
            if ("daoName".equals(field.getName())) {
                modelName = field.get(pjp.getTarget()).toString();
            }
        }
        // 获取将要执行的sql语句所在Mapper
        String daoName = "mapper." + modelName + "Mapper.";
        Object obj = (pjp.getArgs().length > 0 ? pjp.getArgs()[0] : null);// 注意空指针异常
        // 获取执行的修改sql语句
        String sql = sqlSessionFactory.getConfiguration().getMappedStatement(daoName + pjp.getSignature().getName())
                .getBoundSql(obj).getSql();
        // 获取存储sql语句的列表
        List<Map<String, Object>> listMap = (List<Map<String, Object>>) map.get("daoOperation");
        if (listMap == null) {
            listMap = new ArrayList<Map<String, Object>>();
            map.put("daoOperation", listMap);
        }
        Map<String, Object> daoMap = new HashMap<String, Object>();
        listMap.add(daoMap);
        daoMap.put("daoMethodName", pjp.getTarget().getClass().getName() + "." + pjp.getSignature().getName());
        daoMap.put("daoParameter", obj);
        daoMap.put("daoType", "添加");
        daoMap.put("daoSql", sql.replaceAll("\n", ""));
        daoMap.put("start", System.currentTimeMillis());
        Object value = pjp.proceed();
        daoMap.put("return", value);
        daoMap.put("runTime", System.currentTimeMillis() - ((Long) daoMap.get("start")));
        // 向卡夫卡发送日志信息
        log.debug("-----------------//" + JSONObject.toJSONString(daoMap));
        return value;
        // }else {
        // Object value = pjp.proceed();
        // return value;
        // }
    }
}

** 自定义注解:**

 @Target({ElementType.PARAMETER,ElementType.METHOD}) //ElementType.PARAMETER 方法参数,ElementType.METHOD 方法(表示这个注解是方法的注解) 
@Retention(RetentionPolicy.RUNTIME) //注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Documented//说明该注解将被包含在javadoc中
public @interface InsertLog {
    String description() default "";
    String versions() default "";
}

** 主要配置 spring-base : **

<context:annotation-config />

<!-- 配置要扫描的包 -->
<context:component-scan base-package="com.company.project" />

<!-- proxy-target-class默认"false",更改为"ture"使用CGLib动态代理 -->
<aop:aspectj-autoproxy proxy-target-class="true" />

 <!-- 引入配置文件 -->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="locations">
        <list>
            <value>classpath:db.properties</value>
             <value>classpath:redis.properties</value>
        </list>
    </property>
</bean>
<import resource="classpath:spring/spring-dubbo-provider.xml" />
<import resource="classpath:spring/spring-mybatis.xml" />
<!-- <import resource="classpath:spring/spring-redis.xml" /> -->
  • 写回答

5条回答 默认 最新

  • _1_1_7_ 2016-07-07 08:12
    关注

    @Pointcut("execution(* com.company.project.service.user.base.BaseDao+.insert*(..))")

    加个 + 符合试试

    评论
  • _1_1_7_ 2016-07-07 09:21
    关注

    你的需求是:
    在子类UserLoginDaoImpl 中调用insertSelective方法时拦截,
    而父类自己直接调用insertSelective,不拦截?
    感觉描述和理解上有点问题

    评论
  • lsn丶 2016-07-07 09:46
    关注

    u011606457 1_1_7 2016.07.07 17:21
    采纳
    你的需求是:
    在子类UserLoginDaoImpl 中调用insertSelective方法时拦截,
    而父类自己直接调用insertSelective,不拦截?
    感觉描述和理解上有点问题

    可能我之前描述的有些容易误解的地方,

    我想在子类方法addUserlogin 调用父类 insertSelective方法时 在这中间切一下,针对父类方法做环绕

    想要的流程是:

    1.addUserlogin --> 2. insertDaoAspect( 包含insertSelective方法的信息 ) --> 3.insertSelective

    现在问题是第2步没有走,直接到第3步了。

    然后我尝试了 使用 + 号的方式,

    我发现第2步依旧没有调用

    然后我修改了拦截规则 将 .BaseDao.insert*(..) 改成 .BaseDao+.*(..)

    这时候我发现它的执行流程变为了:

    insertDaoAspect( 包含addUserlogin方法的信息 ) --> 1.addUserlogin --> 3.insertSelective

    依旧没有调用第2步方法

    评论
  • GreenRookie 2016-07-07 10:03
    关注

    http://blog.csdn.net/fiangasdre/article/details/51729347 你对比下我这篇 我是实现了

    评论
  • weixin_37536418 2021-07-12 00:08
    关注

    这个问题有解决没,我也遇到类似的

    评论

报告相同问题?

悬赏问题

  • ¥30 android百度地图SDK海量点显示标题
  • ¥15 windows导入environment.yml运行conda env create -f environment_win.yml命令报错
  • ¥15 这段代码可以正常运行,打包后无法执行,在执行for内容之前一直不断弹窗,请修改调整
  • ¥15 C语言判断有向图是否存在环路
  • ¥15 请问4.11到4.18以及4.27和4.29公式的具体推导过程是怎样的呢
  • ¥20 将resnet50中的卷积替换微ODConv动态卷积
  • ¥15 通过文本框输入商品信息点击按钮将商品信息列举出来点击加入购物车商品信息添加到表单中
  • ¥100 这是什么压缩算法?如何解压?
  • ¥20 upload上传实验报错500,如何解决?(操作系统-windows)
  • ¥15 谁知道 ShaderGraph 那个节点可以接入 Particle System -> Custom Data