• javassist 运行期改类


    https://www.cnblogs.com/baiqiantao/p/10235049.html

    https://www.cnblogs.com/xiaofuge/p/12868742.html

    结论:

    1 加载前可以直接替换,加载(new,loadclass,forname)后要hotspot开端口 

    2 函数入参变量使用$1, $2,数组参数$2[0];成员变量用变量名

    3 函数中,所有类要用类全名(包括同包),除了String,可能属于启动类加载器

    4 空格 无关紧要

    5 泛型不可用

    碰到的问题:

    1 泛型不可用

    2 javassist.CannotCompileException: [source error] no such class 用全限定名

    package javassisttest;
    
    import lc.A;
    import javassisttest.ByRef;
    
    /**
     * Created by joyce on 2020/7/29.
     */
    public class ByMod {
    
        /**
         * 测试
         * 1 是否能加载器/加载后替换函数体
         * 加载前可以直接替换,加载后要hotspot开端口
         * 2 局部变量引用
         * 要用$1 $2
         * 3 局部数组变量引用
         * $x[0] $x[1]
         * 4 String.class是否能引用到,是否需要java.lang.String.class
         * 不需要,可能启动类加载器的不需要
         * 5 
     空格  	
         * 6 用全名引用类,import无用,同包无用
         * 7 泛型不可用
         */
        public static final String MODIFIED = "{System.out.println("javassist " + mem +  $1 + $2[0] + String.class + ", modified");
    " +
                "   	System.out.println("done");
    " +
                "   	System.out.println(lc.A.class);
    " +
             //7   "Class<? extends java.lang.Object> o = null;" +
                "   	System.out.println(javassisttest.ByRef.class);
    }";
    
        /**
         * 测试
         * 1 函数内如何引用成员变量
         */
        private String mem = "memval";
    
        /**
         * 测试
         * 1 数组类型入参
         * 2 函数内如何引用方法局部变量
         * @param xxx
         * @param objects
         */
        public void print(String xxx, Object [] objects) {
            System.out.println("not yet mod");
            Class<? extends Object> o = null;
        }
    }
    
    package javassisttest;
    
    import javassist.ClassPool;
    import javassist.CtClass;
    import javassist.CtMember;
    import javassist.CtMethod;
    
    import static javassisttest.ByMod.MODIFIED;
    
    /**
     * Created by joyce on 2020/7/29.
     */
    public class ModerBeforeLoad {
    
        public static void main(String [] f) throws Exception {
            ClassPool pool = ClassPool.getDefault();
            CtClass cc = pool.get("javassisttest.ByMod");
            CtMethod cm = cc.getDeclaredMethod("print", new CtClass[]{pool.get("java.lang.String"), pool.get("java.lang.Object[]")});
            cm.setBody(MODIFIED);
            cc.toClass();
            ByMod byMod = new ByMod();
            byMod.print("be", new String[]{"heefsf"});
        }
    }
    

     输出:

    javassist memvalbeheefsfclass java.lang.String, modified
    done
    class lc.A
    class javassisttest.ByRef

    package javassisttest;
    
    import com.sun.org.apache.xpath.internal.operations.Mod;
    import javassist.ClassPool;
    import javassist.CtClass;
    import javassist.CtMethod;
    import javassist.util.HotSwapper;
    import lc2.E;
    
    import static javassisttest.ByMod.MODIFIED;
    
    /**
     * Created by joyce on 2020/7/29.
     */
    public class ModerAfterLoad {
        public static void main(String [] f) throws Exception {
            /**
             * 这三种方式都会造成
             * by java.lang.LinkageError: loader (instance of  sun/misc/Launcher$AppClassLoader):
             * attempted  duplicate class definition for name: "javassisttest/ByMod"
             */
    //        ByMod byMod = new ByMod();
    //        Class.forName("javassisttest.ByMod");
            ModerAfterLoad.class.getClassLoader().loadClass("javassisttest.ByMod");
    
            ClassPool pool = ClassPool.getDefault();
            CtClass cc = pool.get("javassisttest.ByMod");
            CtMethod cm = cc.getDeclaredMethod("print", new CtClass[]{pool.get("java.lang.String"), pool.get("java.lang.Object[]")});
            cm.setBody(MODIFIED);
            try {
                cc.toClass();
            } catch (Exception e) {
                System.out.println(e.getMessage());
            }
    
            ByMod byMod = new ByMod();
            byMod.print("he", new String[]{"xxx"});
    
            // idea VM : -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
            HotSwapper hs = new HotSwapper(8000);
            hs.reload(ByMod.class.getName(), cc.toBytecode());
    
            byMod.print("he", new String[]{"xxx"});
        }
    }
    

    输出:

    Listening for transport dt_socket at address: 8000
    by java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "javassisttest/ByMod"
    not yet mod
    javassist memvalhexxxclass java.lang.String, modified
    done
    class lc.A
    class javassisttest.ByRef

    实践:myorm【重点】$$27

    @Target({ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ToBeInterceptedForMapper {
        Class<? extends MapperProcessor> mapperProcessor();
    

      

    abstract public class AbstractTimezoneProcessor extends DefaultMapperProcessor {
    
        @Override
        public Object execute() throws Exception {
            Object target = super.getValue();
            Class c = target.getClass();
            Method method = super.getMethod();
            logger.info("mapper aop {} - {}.{}", this.getClass().getName(), c, method);
            //return doExecute();
            return super.execute();
        }
    
        private Object doExecute() throws Exception {
    
            Object target = super.getValue();
            Class c = target.getClass();
            Method method = super.getMethod();
            Object[] args = super.getArgs();
    
            ToBeInterceptedForMapper annotation = (ToBeInterceptedForMapper)method.getAnnotation(ToBeInterceptedForMapper.class);
    
            if(annotation != null) {
                return doTimezoneProcessor();
            } else {
                logger.error("error timezone aop : {}, {}, {}", c, method, args);
                return method.invoke(target, args);
            }
        }
    
        abstract protected Object doTimezoneProcessor() throws Exception;
    
        abstract protected Date turnDate(Date origin, int dbZone);
    
        protected void setDate(Object obj, int dbZone) throws Exception {
    
            Class cl = obj.getClass();
            Field[] fields = cl.getDeclaredFields();
    
            for (Field field : fields) {
                field.setAccessible(true);
    
                if(!java.util.Date.class.isAssignableFrom(field.getType()))
                    continue;
    
                if (Modifier.isStatic(field.getModifiers()))
                    continue;
    
                if (field.isAnnotationPresent(SCEF_DB_NO_FIELD.class))
                    continue;
    
                if(field.get(obj) == null)
                    continue;
    
                Date date = (Date)field.get(obj);
                Date tranzDate = turnDate(date, dbZone);
                field.set(obj, tranzDate);
            }
        }
    

      

    public class TimezoneProcessorForInsertAndUpdate extends AbstractTimezoneProcessor {
    
        @Override
        protected Object doTimezoneProcessor() throws Exception {
            Object target = super.getValue();
            Method method = super.getMethod();
            Object[] args = super.getArgs();
    
            int dbZone = -4;
    
            setDate(args[0], dbZone);
            Object res = method.invoke(target, args);
    
            return res;
        }
    
        @Override
        protected Date turnDate(Date origin, int dbZone) {
            return TimezoneManager.timezoneJvmToDbWhenInsertAndUpdate(origin, dbZone);
        }
    }
    

      

    public class TimezoneProcessorForQuery extends AbstractTimezoneProcessor {
    
        @Override
        protected Object doTimezoneProcessor() throws Exception {
            Object target = super.getValue();
            Method method = super.getMethod();
            Object[] args = super.getArgs();
            int dbZone = -4;
    
            Object res = method.invoke(target, args);
            Class resType = res.getClass();
            if(List.class.isAssignableFrom(resType) || Set.class.isAssignableFrom(resType)) {
                Collection collection = (Collection) res;
                Iterator iterator = collection.iterator();
                while (iterator.hasNext()) {
                    Object obj = iterator.next();
                    setDate(obj, dbZone);
                }
            } else {
                setDate(res, dbZone);
            }
    
            return res;
        }
    
        @Override
        protected Date turnDate(Date origin, int dbZone) {
            return TimezoneManager.timezoneDbToJvmWhenQuery(origin, dbZone);
        }
    
    
    }
    

      

  • 相关阅读:
    js获取鼠标的位置
    去掉a标签的虚线框,避免出现奇怪的选中区域
    点击按钮 可以显示隐藏
    input标签获取焦点时文本框内提示信息清空背景颜色发生变化
    ie6下面不支持!important的处理方法
    [zz]【整理】Python中Cookie的处理:自动处理Cookie,保存为Cookie文件,从文件载入Cookie
    [vim]大小写转换
    [zabbix]zabbix2.0apt源安装
    [mysql]replace
    [ethernet]ubuntu更换网卡驱动
  • 原文地址:https://www.cnblogs.com/silyvin/p/13399823.html
Copyright © 2020-2023  润新知