Spring Aop的另类问题

在使用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的值

Spring Aop的另类问题_第1张图片

你可能感兴趣的:(spring,AOP,glibc)