b2科目四模拟试题多少题驾考考爆了怎么补救
b2科目四模拟试题多少题 驾考考爆了怎么补救

Spring AOP无法拦截内部方法调用(2)

电脑杂谈  发布时间:2020-07-08 18:21:10  来源:网络整理

看一个简单的测试示例

第一步: 定义父类

public class Animal {
    public void play() {
        System.out.println("animal play .....");
    }
    public void money() {
        play();
        System.out.println("animal money......");
    }
}

第2步: 模拟CGLib动态代理

js 动态调用成员方法_动态调用 webservice_动态方法调用 为什么不安全

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文件时编织字节码并更改原始类.

js 动态调用成员方法_动态调用 webservice_动态方法调用 为什么不安全

第一步:

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金投赏#棒

      • 刘博蓉
        刘博蓉

        警告后还不是滚出去了

    • 陈梦萱
      陈梦萱

      终有一天会被全世界抛弃

    • 卫成公
      卫成公

      不是说美国是纸老虎吗

    热点图片
    拼命载入中...