zoukankan      html  css  js  c++  java
  • java 的三种代理模式 (二)——子函数切面

    java 的三种代理模式

    结论:

    1 jdk动态代理无法切面子函数,因为jdk动态代理是组合模式,this永远指向被代理origin类的对象,切子函数理论不可行

    public class ProxyFactory implements InvocationHandler {
        //维护一个目标对象
        private Object target;
        public ProxyFactory(Object target){
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("开始事务jdk");
            Object returnValue = method.invoke(target, args);
    

    除非用暴力(asm、javassist)运行期修改子函数 son(xxx)--->proxy.son(xxx)

    2 cglib为继承模式,能够利用java语言的多态的特性,this指针本身指向proxy类对象,使切子函数理论可行

    具体而言,可以切子函数,也可以不切,取决于:

        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("开始事务cglib");
    
            //执行目标对象的方法
        //    Object returnValue = method.invoke(target, args);
    
            // 上面那个直接调用父类对象target的父方法,this指向父类——被代理origin类
            // obj为子类——proxy类对象,this指向proxy对象
            // 在这个地方拦截子函数
            Object returnValue = proxy.invokeSuper(obj, args);
    
        //    Object returnValue = method.invoke(obj, args); 无限循环
    
            System.out.println("提交事务cglib");
    
            return returnValue;
        }
    

    3 spring aop

    Cglib代理的时候target对象中的this就是Cglib子类  (你可能觉得我说的是废话,子类对象在父类的this指的不是自身吗? 你知道Spring Aop里this方法无法增强自身调用,这时候你就开始怀疑人生了)

    spring自己阉割了,https://www.cnblogs.com/lvbinbin2yujie/p/10284316.html,AopUtils

     这也是spring aop 内部方法与aspectJ的原因

    为什么,既然cglib有切子函数的功能,为何spring不用?猜测可能为了与jdk动态代理统一,毕竟后者无法切子函数?还是有更高远的考量?

    一个经典应用:

    @Transactional(propagation = Propagation.REQUIRED)
        public void insertUser1(){
            User user = new User("niu","男",19,"1000000");
            userDao.insertUser(user);
    
            this.insertUser2();
            //异常
            int a = 10/0;
        }
    
        @Transactional(propagation = Propagation.REQUIRES_NEW)
        public void insertUser2(){
            User user = new User("xing","女",19,"1111111");
            userDao.insertUser(user);
        }
    

      https://www.cnblogs.com/nxzblogs/p/10503889.html中

    问题:“service层有两个事务方法insertUser1、insertUser2, 当在insertUser1中调用insertUser2是,如果前面 方法异常,后边方法不会保存

      期望:不管insertUser1是否报错,insertUser2 都要报存数据”

    子方法的事务不起作用,继承母方法一起回滚

    4 cglib解决无限递归

    public final void mother() {
    MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
    if (var10000 == null) {
    CGLIB$BIND_CALLBACKS(this);
    var10000 = this.CGLIB$CALLBACK_0;
    }

    if (var10000 != null) {
    var10000.intercept(this, CGLIB$mother$0$Method, CGLIB$emptyArgs, CGLIB$mother$0$Proxy);
    } else {
    super.mother();
    }
    }
    //    Object returnValue = method.invoke(obj, args); 无限循环

    5 protected和public子函数可切,private不可切,因为private函数无法overide

    当然,此外final function也是无法用cglib代理的,因为无法override

    6 建议优先使用cglib增强,及protected子函数,极端情况使用private

    在某些场景,具有优势

    比如,所有方法的输入、输出统一全过程日志,cglib可以切到子函数,jdk proxy切不到,只能在子函数前后单独log,侵入较高,未利用代理中控的集中性

    运用cglib增强配合 spring批量注入结合自定义注解的 spring 动态注入 ,构建自定义spring aop,弥补spring aop对切子函数的不友好的缺点(每个子函数getbean,侵入较高)

    7 可以被切的隐藏方法(在java object常用方法罗列的方法),即时origin不改写这些方法,框架也会加上

    object:clone finalize equals toString hashCode getClass wait notify notifyAll

    jdk: equals toString hashcode

    cglib:clone finalize equals toString hashCode

    参考:

    https://www.cnblogs.com/lvbinbin2yujie/p/10284316.html

    https://blog.csdn.net/qq_28033719/article/details/108339751

  • 相关阅读:
    单源最短路——SPFA算法(Bellman-Ford算法队列优化)
    A Compatible Pair
    欧拉函数知识点总结及欧拉函数打表代码(数论)
    Fafa and the Gates(模拟)
    C语言--链表基础模板
    路由器如何设置上网(TP-LINK)
    学员成绩管理系统
    Bad Cowtractors(最大生成树)
    Agri-Net(最小生成树)
    Median Weight Bead(最短路—floyed传递闭包)
  • 原文地址:https://www.cnblogs.com/silyvin/p/13756883.html
Copyright © 2011-2022 走看看