方法动态代理

Service Keeper提供了原始方法的代理工具类用来完成对原始方法的代理,并织入服务治理的相关功能。使用时需要引入包:

<dependency>
    <groupId>io.esastack</groupId>
    <artifactId>servicekeeper-proxy-adapter</artifactId>
    <version>${servicekeeper.version}</version>
</dependency>

<dependency>
    <groupId>io.esastack</groupId>
    <artifactId>commons</artifactId>
    <version>${esa.commons.version}</version>
</dependency>
Note

使用该方式接入Service Keeper时需要在应用启动时主动调用ServiceKeeperAsyncInvoker的init()完成对配置文件的监听,否则只有当第一调用ServiceKeeperAsyncInvoker中的方法时才会建立对配置文件的监听。

动态代理默认会拦截对象中所有能被代理到的方法,使用方式根据被代理的类是否为接口而略有不同,具体如下:

  • 情形一:代理类为接口:

    接口定义示例:

    public interface DemoService {
      @RateLimiter(limitForPeriod = 100)
      void sayHello();
    }
    

    实现类示例:

    public class DemoServiceImpl implements DemoService {
      @Override
      public void sayHello() {
    
      }  
    }
    

Service Keeper治理示例:

// 使用ServiceKeeper提供的代理工厂创建接口的代理类
DemoService demoService = ServiceKeeperProxyFactory.createProxyHasInterface(new DemoServiceImpl());

// 执行方法调用
demoService.sayHello();    
Note

该情形下服务治理注解需要加在接口方法上

  • 情形二:代理类为非接口:

    原始类定义示例:

public class DemoServiceImpl {
    @Override
    @RateLimiter(limitForPeriod = 100)
    public String merge(String s1, String s2) {
        return s1 + s2;
    }
}

Service Keeper代理示例:

// 使用ServiceKeeper提供的代理工厂创建非接口的代理类
DemoServiceImpl demoService = ServiceKeeperProxyFactory.createProxyNoInterface(new DemoServiceImpl());

// 执行方法调用
demoService.sayHello();
Note

该情形下服务治理注解需要加在类方法上

工具类

Service Keeper提供了工具类,在原始方法执行前后织入服务治理的相关功能,具体方法如下:

public final class ServiceKeeperInvoker {

    private ServiceKeeperInvoker() {
    }
    
    public static Object invoke(Method method, Object delegate, Object[] args) throws Throwable {
        return Bootstrap.entry().invoke(method, delegate, args);
    }

    public static Object invoke(String aliasName, Method method, Object delegate, Object[] args) throws Throwable {
        return Bootstrap.entry().invoke(aliasName, method, delegate, args);
    }

    public static <T> T call(String name, CompositeServiceKeeperConfig immutableConfig,
                             Callable<T> callable, Object[] args) throws Throwable {
        return Bootstrap.entry().call(name, immutableConfig, callable, args);
    }

    public static <T> T call(String name, Callable<T> callable, Object[] args) throws Throwable {
        return Bootstrap.entry().call(name, callable, args);
    }

    public static <T> T call(String name, CompositeServiceKeeperConfig immutableConfig,
                             OriginalInvocation originalInvocation, Callable<T> callable,
                             Object[] args) throws Throwable {
        return Bootstrap.entry().call(name, immutableConfig, originalInvocation,
                callable, args);
    }
    
    public static <T> T call(String name, Supplier<CompositeServiceKeeperConfig> immutableConfigSupplier,
                             Supplier<OriginalInvocation> originalInvocation, Callable<T> callable,
                             Object[] args) throws Throwable {
        return Bootstrap.entry().call(name, immutableConfigSupplier, originalInvocation,
                callable, args);
    }

    public static void run(String name, Runnable runnable, Object[] args) throws Throwable {
        Bootstrap.entry().run(name, runnable, args);
    }

    public static void run(String name, CompositeServiceKeeperConfig immutableConfig,
                           Runnable runnable, Object[] args) throws Throwable {
        Bootstrap.entry().run(name, immutableConfig, runnable, args);
    }
    
    public static void init(List<AsyncResultHandler<?>> asyncResultHandlers) {
        Bootstrap.init(BootstrapContext.singleton(asyncResultHandlers));
    }
}

其中,name用于指定当前调用的名称,与配置文件中的配置的名称或管控平台的资源ID对应 CallbaleRunnable用于封装原始的执行逻辑。 OriginalInvocationInfo提供原始方法的返回值、参数列表信息,在匹配降级方法时使用(可选)。 CompositeServiceKeeperConfig提供当调用的初始配置(可选)。 举例说明: 自定义HelloService如下:

public class HelloService {

    public String sayHello(String name) {
        return "Hello " + name + "!";
    }

}

使用ServiceKeeper封装逻辑如下:

public static void main(String[] args) throws Throwable {

    final HelloService service = new HelloService();
    final Callable<String> callable = () -> service.sayHello("LiMing");

    ServiceKeeperInvoker.call("helloservice.hello", callable, new Object[]{"LiMing"});

}

如上所示,"helloservice.hello"表示当前callable的名称,通过配置文件或者管控平台配置该名称的限流、熔断等配置将对当前callbale生效;new Object[]{"LiMing"}是用来对当前callbable做参数级服务治理,如果不需该功能可以直接使传递new Object[0]。