Вызовите метод в любое время, когда вызываются другие методы

существует ли какой-нибудь "суперметод", который вызывается каждый раз, когда вызывается метод, даже для неопределенных методов? Пример:

public void onStart() {
    System.out.println("Start");
}

public void onEnd() {
    System.out.println("End");
}

public SuperMethod superMethod() {
    System.out.println("Super");
}

// "Start"
// "Super"
onStart();

// "End"
// "Super"
onEnd();

// "Super"
onRun();

Спасибо за любую помощь.

Изменить - Спецификации: У меня есть библиотека, которая много обновляет и получает повторное пробуждение при каждом обновлении. Чтобы упростить мой рабочий процесс, я делаю свою программу автоматически обновляющей библиотеку (требуется для выполнения того, что я хочу, я не буду говорить об этом, но моя программа будет работать с будущими обновлениями), и у меня есть сопоставление обфускации с помощью Я хочу создать прокси-сервер под названием Library, а затем, когда я вызову Library.getInstance(), он получит сопоставление обфускации для getInstance() и вызовет библиотечный метод getInstance() или abz по мере его отображения в данный момент времени.

Ответ 1

Вот реализация в чистой Java, используя класс Proxy:

import java.lang.reflect.*;
import java.util.*;

public class Demo
{
    public static void main(String[] args)
    {
        Map<String, String> map = new HashMap<String, String>();
        map.put("onStart", "abc");
        map.put("onEnd", "def");
        Library library = new LibraryProxy(map, new LibraryImpl()).proxy();
        library.onStart();
        library.onEnd();
        library.onRun();
    }
}

interface Library
{
    void onStart();
    void onEnd();
    void onRun();
}

class LibraryImpl
{
    public void abc() { System.out.println("Start"); }
    public void def() { System.out.println("End"); }
}

class LibraryProxy implements InvocationHandler
{
    Map<String, String> map;
    Object impl;

    public LibraryProxy(Map<String, String> map, Object impl)
    {
        this.map = map;
        this.impl = impl;
    }

    public Library proxy()
    {
        return (Library) Proxy.newProxyInstance(Library.class.getClassLoader(),
            new Class[] { Library.class }, this);
    }

    @Override
    public Object invoke(Object proxy, Method m, Object[] args) throws Throwable
    {
        Object res = null;
        String name = map.get(m.getName());
        if (name == null) {
            System.out.println("[" + m.getName() + " is not defined]");
        } else {
            m = impl.getClass().getMethod(name, m.getParameterTypes());
            res = m.invoke(impl, args);
        }
        System.out.println("super duper");
        return res;
    }
}

Вывод:

Start
super duper
End
super duper
[onRun is not defined]
super duper

Ответ 2

Конечно, вы можете это сделать, а не со стандартным java, но с AspectJ

Вот простой пример:

Аспект с последующим советом

package net.fsa.aspectj.test;


public aspect SuperMethdAspect {

    pointcut afterPointCut() : execution(public * com.my.pack.age.MyClass.*(..));

    after() : afterPointCut() {
        System.out.println("Super");
    }
}

Целевой класс

package com.my.pack.age;

public class MyClass {

    public void onStart() {
        System.out.println("Start");
    }

    public void onEnd() {
        System.out.println("End");
    }
}

И, наконец, какое-то тестовое приложение

package net.fsa.aspectj.test;

import com.my.pack.age.MyClass;

public class MyApp {

    public static void main(String... args) {
        MyClass myClass = new MyClass();
        myClass.onStart();
        myClass.onEnd();
    }
}

Выход

Start
Super
End
Super

Ответ 3

Java действительно не допускает такую ​​магию. Для того, чтобы вызов произошел, он должен появиться внутри вашего (скомпилированного) кода. Таким образом, ответ отрицательный, не без явного добавления вызова к соответствующим методам. Однако вы можете скрыть это несколько с помощью генерации кода препроцессора или времени выполнения.

Я думаю, что AspectJ может быть тем, что вы хотите.

Ответ 4

Я предполагаю, что это не совсем то, что вы хотите, но вы можете обернуть весь код в методах в try {}finally {supermethod ()}. Это будет гарантировать, что суперметод называется.

Ответ 5

Термин, стоящий за этим понятием, называется перехватчиком. Вам нужен контейнер, который делает это как ApplicationServer, CDI Container, Spring или AOP. Он работает следующим образом

1. call your Method
2. pause your Method
3. call intercepter
4. do interceptor stuff
5. resume your Method inside the interceptor