看一个简单的测试示例
第一步: 定义父类
public class Animal {
public void play() {
System.out.println("animal play .....");
}
public void money() {
play();
System.out.println("animal money......");
}
}
第2步: 模拟CGLib动态代理

public class Animal#dog extends Animal {
public final void play() {
System.out.println("dog play start22222.....");
super.play();
System.out.println("dog play end......");
}
public final void money() {
System.out.println("dog money start.......");
super.money();
System.out.println("dog money end......");
}
}
第三步: 模拟客户端
public class MainDemo {
public static void main(String[] args) {
Animal animal = new Animal#dog();
animal.money();
}
}
测试结果:
dog money start.......
dog play start22222.....
animal play .....
dog play end......
animal money......
dog money end......
因为new是子类的对象,而不是父类的对象,所以在调用父类的money之后,this.play()会在父类的money中被调用;
但是this.play()不是在父类中播放,而是play();在子类Animal#dog中,因为新对象在内部存储了父类,而不是子类中的对象.
也就是说,如果Spring Aop使用CGLib作为动态代理动态方法调用 为什么不安全,则可以避免上述内部呼叫有效性问题.
第一步:
内部调用不走代理解决方法:<aop:aspectj-autoproxy expose-proxy="true" />
第二步:
使用AopContent((PerformanceService)AopContext.currentProxy()). music();直接进行操作
@Service
public class PerformanceServiceImpl implements PerformanceService {
public void play() {
System.out.println("start performance......"+this.getClass());
((PerformanceService) AopContext.currentProxy()).music();
//music();
}
public void music() {
System.out.println("play music........."+this.getClass());
}
}
AspectJ将在编译Java文件时编织字节码并更改原始类.

第一步:
public class MusicDome {
public void play() {
System.out.println("play music...." + this.getClass());
music();
}
public static void main(String[] args) {
MusicDome dome = new MusicDome();
dome.play();
System.out.println("main====" + dome.getClass());
}
public void music() {
System.out.println("musice......" + this.getClass());
}
}
第2步: 在编译和编译过程中进行编织
public aspect AspectJDome {
//pointcut callPointCut():call(void com.test.proxy.sound.MusicDome.play());
//测试方法内部调用是否走了这里
/**
* 研究发现,静态编译织入和动态代理还是很不一样,动态代理是生成一个代理对象,然后代理你去做事情;
* 但是静态编译织入,虽然也是代替你执行一些事情,但是他不是生成一个动态代理类,而是在你原有的类中在编译期间去改变你原有的类,在原有的
* 类中加入一些事情。
*
*/
pointcut callPointCut():call(void com.test.proxy.sound.MusicDome.*());
before():callPointCut(){
System.out.println();
System.out.println("-------AspectJ log--------");
System.out.println("signature:"+thisJoinPoint.getStaticPart().getSignature());
System.out.println("------------end---------");
}
}
打印结果:
-------AspectJ log--------
signature:void com.test.proxy.sound.MusicDome.play()
------------end---------
play music....class com.test.proxy.sound.MusicDome
-------AspectJ log--------
signature:void com.test.proxy.sound.MusicDome.music()
------------end---------
musice......class com.test.proxy.sound.MusicDome
main====class com.test.proxy.sound.MusicDome
发现在编译时进行编织时没有内部调用失败的问题.
我们都知道Demo.java文件不能直接被允许,但是必须由编译器编译成Demo.class类字节代码,以便jvm虚拟机可以识别它.
AspectJ通过编译器Demo.java->添加一些增强功能-> Demo.class进行编译.
让我们看看在编译过程中编织的代码
public class MusicDome {
public void play() {
System.out.println("-------AspectJ log--------");
System.out.println("play music...." + this.getClass());
music();
System.out.println("-------end--------");
}
public static void main(String[] args) {
MusicDome dome = new MusicDome();
dome.play();
System.out.println("main====" + dome.getClass());
}
public void music() {
System.out.println("-------AspectJ log--------");
System.out.println("musice......" + this.getClass());
System.out.println("-------end--------");
}
}
AspectJ在编译过程中将增强的代码编织到原始类中,因此无论您怎么称呼它,都不会产生影响.
JDK动态代理和CGLIB字节码生成有什么区别?
-JDK动态代理只能为实现该接口的类生成代理,而不能为该类生成代理
-CGLIB将实现类的代理,主要是为指定的类生成一个子类,并覆盖其中的方法. 因为它是继承的,所以最好不要将类或方法声明为final,static或private,这将导致代理失败.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/tongxinshuyu/article-273206-2.html
警告后还不是滚出去了
终有一天会被全世界抛弃
不是说美国是纸老虎吗
#杨洋icon##杨洋2015金投赏#棒