当前位置: 首页 > news >正文

Spring Aop的另类问题

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

在使用Spring Aop的时候遇到一个问题,假如我们有如下的几个类(简单起见用的spring的注解配置,不过换成xml配置问题也是一样的):

1. 一个基类,是否是abstract无所谓,关键点是它具有一个default权限的成员函数,并且该成员函数访问了基类的一个成员属性,如代码中的getTime()方法:

package org.fox;

public abstract class TimeService {
	private long time = 0L;

	public void setTime() {
		time = System.currentTimeMillis();  }

	long getTime() {
		return time;
	}
}
2. 子类,子类如何实现不是重点,他可以单纯的继承基类,重点是 它和基类不在同一个包中
package org.fox.impl;

import org.fox.TimeService;
import org.springframework.stereotype.Component;

@Component
public class SystemTimeService extends TimeService {
}

3.一个Aspect,为TimeService的bean织入一个过程,这里简单的就system.out

package org.fox;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class Log {
	@Before("execution(* TimeService.*(..))")
	public void log() {
		System.out.println("log");
	}
}
Spring的bean配置文件为:


<context:annotation-config />
<context:component-scan base-package="org.fox" />
<aop:aspectj-autoproxy proxy-target-class="true" />
现在的问题是,如下代码getTime()的返回值是什么。
TimeService service = context.getBean(TimeService.class);
service.setTime();
System.out.println(service.getTime());

这个问题来自项目里面自己实现的DataCache模块,按照常理讲,setTime()和getTime()都是基类TimeService定义的,子类没有做任何的改变,getTime()应该返回的是当前时间毫秒值才对。但是,实际上因为cglib的原因,结果是0。



对代码打上断点后才发现问题的所在,为达到Aspect的目的,cglib产生了原类(SystemTimeService)的一个子类,这个子类和SystemTimeService在同一个包下,对于一般的被代理的方法,通过super便可以简单调用,但是问题是这个getTime()方法,因为他是基类定义的default方法,作为不在同一个包下的子孙类,是无法调用它的。从结果上看,cglib放弃了用反射绕过权限控制的做法,而是将原类中的成员属性以及这个getTime()方法复制了一份定义到代理类中。

这样实际上TimeService bean实例中是存在有两个不同的time成员属性,public的setTime()方法由于代理类可以通过super直接调用,所以他操作的是原本TimeService定义的time,而getTime()则因为在代理类中重新定义,所以他返回的是代理类自己定义的time属性,这就是上面问题为0的原因了。解决方法按照上面的思路也很容易想到,只需要给子类有调用getTime()的权限,把访问权限改成protected即可。



实例如下图,注意this和target下的lastUpdate的值

转载于:https://my.oschina.net/shishuifox/blog/122455

相关文章:

  • vs2010创建Web Service程序
  • 宋体、文件-Ubuntu Linux中配置adb-by小雨
  • 测试数据整数搜索——Ny 90 整数划分
  • 类的静态成员
  • GE打造工业互联网
  • 如何让JTable的内容显示 居中
  • 最大堆、最小堆操作-删除、
  • 日期条件SQL 截取日期作为条件
  • 《Head First设计模式》 读书笔记10 迭代器与组合模式 The Iterator and Composite Patterns...
  • CodeLobster PHP Edition v4.5.3 Professional 注册码
  • js ol.ui.alternation
  • ZOJ-3699 Dakar Rally 单调队列
  • sql server分页存储过程
  • 通用权限管理系统组件从实现基本功能到让别人欣赏软件,把每个细节都做精做彻底...
  • nfs客户端无法chown
  • @jsonView过滤属性
  • 0基础学习移动端适配
  • 2017届校招提前批面试回顾
  • CentOS7简单部署NFS
  • CNN 在图像分割中的简史:从 R-CNN 到 Mask R-CNN
  • Cookie 在前端中的实践
  • Invalidate和postInvalidate的区别
  • Java的Interrupt与线程中断
  • mockjs让前端开发独立于后端
  • Node + FFmpeg 实现Canvas动画导出视频
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • SOFAMosn配置模型
  • UEditor初始化失败(实例已存在,但视图未渲染出来,单页化)
  • webpack入门学习手记(二)
  • 从地狱到天堂,Node 回调向 async/await 转变
  • 基于MaxCompute打造轻盈的人人车移动端数据平台
  • 区块链共识机制优缺点对比都是什么
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 入门到放弃node系列之Hello Word篇
  • 提醒我喝水chrome插件开发指南
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • linux 淘宝开源监控工具tsar
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • ​Spring Boot 分片上传文件
  • ​业务双活的数据切换思路设计(下)
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • %check_box% in rails :coditions={:has_many , :through}
  • (NO.00004)iOS实现打砖块游戏(九):游戏中小球与反弹棒的碰撞
  • (学习日记)2024.03.12:UCOSIII第十四节:时基列表
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • ***检测工具之RKHunter AIDE
  • .NET BackgroundWorker
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .NET CORE使用Redis分布式锁续命(续期)问题
  • .NET 设计模式—适配器模式(Adapter Pattern)
  • .Net6 Api Swagger配置
  • .Net的C#语言取月份数值对应的MonthName值
  • [ element-ui:table ] 设置table中某些行数据禁止被选中,通过selectable 定义方法解决
  • [100天算法】-实现 strStr()(day 52)