Я никогда не работал с cglib, однако я знаю, что с Javassist вы можете использовать обработчики вызовов для получения экземпляра класса, а затем есть всевозможные способы нацеливания чего-либо без изменения его аннотаций.Один из моих любимых способов - подключиться к методу, который не находится внутри этого класса, но вызывает его, затем, когда он вызывает метод внутри этого класса, он может вносить изменения в уровень байт-кода или использовать немного более медленный, но читаемый человеком высокий уровень.Уровень api, чтобы внести ваши коррективы.
Это фрагмент из моего работающего кода, который работал более 2 лет без проблем.Это использует javassist.
ClassPool myPool = new ClassPool(ClassPool.getDefault());
myPool.appendClassPath("./mods/bountymod/bountymod.jar");
CtClass ctTHIS = myPool.get(this.getClass().getName());
ctCreature.addMethod(CtNewMethod.copy(ctTHIS.getDeclaredMethod("checkCoinBounty"), ctCreature, null));
ctCreature.getDeclaredMethod("modifyFightSkill").instrument(new ExprEditor() {
public void edit(MethodCall m)
throws CannotCompileException {
if (m.getClassName().equals("com.wurmonline.server.players.Player")
&& m.getMethodName().equals("checkCoinAward")) {
String debugString = "";
if (bDebug)
debugString = "java.util.logging.Logger.getLogger(\"org.gotti.wurmunlimited.mods.bountymod.BountyMod"
+ "\").log(java.util.logging.Level.INFO, \"Overriding checkCoinAward to checkCoinBounty\");\n";
m.replace(debugString + "$_ = checkCoinBounty(player);");
}
}
});
Получает пул классов по умолчанию.Затем добавляет конец для статического класса, из которого мы хотим получить метод.Однако этот метод находится не в последнем классе, а в классе мода, который мы внедряем в исходный jar во время выполнения.Затем он получает метод внутри этого класса.Затем он получает весь classPool каждого класса, который связан с одним экземпляром класса, который мы получили от myPool.Почему это ограничивает объемы, с которыми мы сталкиваемся или можем испортиться, занимает немного памяти во время генерации кода.
Затем он добавляет новый метод в ctCreature, который является классом, который мы инициировали в переменной.раньше сожалею об этом.Метод создается в этом классе, но затем копируется в другой класс, откуда мы хотим его использовать.Затем он подключается к объявленному методу modifyFightSkill, что в данном случае происходит именно тогда, когда мы хотим, чтобы наш код вызывался.Поэтому, когда он запускается, мы запускаем новый редактор выражений.
Этот редактор выражений затем проверяет, что реальный класс, в котором мы хотим быть, но не испортил его первоначальную конструкцию, и получает метод внутри этогокласс, с которым мы хотим что-то сделать, не изменяя его базовый класс.
Как только это произойдет, и все будет проверено с помощью ifs и положительных героев, метод затем заменяет исходный метод нашим новым методом через replace.Вынимает старую, вставляет новую. Все ваши аннотации из класса, в котором они содержатся, не тронуты, потому что мы незаметно вошли со стороны.
Теперь мы могли просто прыгнуть прямо в нужный нам класс, воспользоваться этим методом и сделать то, что мы хотим.Однако мы бы столкнулись с проблемами, или испортили конструкторы или другие вещи.То, как вы подходите к внедрению кода, очень важно при работе с большим проектом.
Возможно, этот ответ был довольно длинным, но InvokationHandler поначалу может быть немного сложно понять.