Skip to content

Commit

Permalink
添加生命周期适配器让用户选择实现指定生命周期方法;Command和Http路径兼容路径/前缀;添加后置事件,无论方法正常返回还是抛出异常都执行;
Browse files Browse the repository at this point in the history
  • Loading branch information
dadiyang committed Apr 7, 2019
1 parent 5ff3554 commit c749290
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.alibaba.jvm.sandbox.api;

/**
* 模块生命周期适配器,用于简化接口实现
*
* @author dadiyang
* @since 2019/4/7
*/
public class ModuleLifecycleAdapter implements ModuleLifecycle {
@Override
public void onLoad() throws Throwable {
}

@Override
public void onUnload() throws Throwable {

}

@Override
public void onActive() throws Throwable {

}

@Override
public void onFrozen() throws Throwable {

}

@Override
public void loadCompleted() {

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,19 @@ private void switchEvent(final OpStack opStack,
final ReturnEvent rEvent = (ReturnEvent) event;
final WrapAdvice wrapAdvice = opStack.popByExpectInvokeId(rEvent.invokeId);
if (null != wrapAdvice) {
adviceListener.afterReturning(wrapAdvice.advice.applyReturn(rEvent.object));
Advice advice = wrapAdvice.advice.applyReturn(rEvent.object);
adviceListener.afterReturning(advice);
adviceListener.after(advice);
}
break;
}
case THROWS: {
final ThrowsEvent tEvent = (ThrowsEvent) event;
final WrapAdvice wrapAdvice = opStack.popByExpectInvokeId(tEvent.invokeId);
if (null != wrapAdvice) {
adviceListener.afterThrowing(wrapAdvice.advice.applyThrows(tEvent.throwable));
Advice advice = wrapAdvice.advice.applyThrows(tEvent.throwable);
adviceListener.afterThrowing(advice);
adviceListener.after(advice);
}
break;
}
Expand Down Expand Up @@ -157,6 +161,14 @@ private void switchEvent(final OpStack opStack,
target.callJavaMethodName,
target.callJavaMethodDesc
);
adviceListener.afterCall(
wrapAdvice.advice,
target.callLineNum,
target.callJavaClassName,
target.callJavaMethodName,
target.callJavaMethodDesc,
null
);
break;
}

Expand All @@ -179,6 +191,14 @@ private void switchEvent(final OpStack opStack,
target.callJavaMethodDesc,
ctEvent.throwException
);
adviceListener.afterCall(
wrapAdvice.advice,
target.callLineNum,
target.callJavaClassName,
target.callJavaMethodName,
target.callJavaMethodDesc,
ctEvent.throwException
);
break;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ public class AdviceListener {
* @throws Throwable 处理通知错误
*/
protected void before(Advice advice) throws Throwable {

}

/**
Expand All @@ -50,6 +49,17 @@ protected void afterReturning(Advice advice) throws Throwable {

}

/**
* 方法调用后通知,无论是正常返回还是抛出异常都会调用
*
* @param advice 通知信息
* @throws Throwable 处理通知错误
* @see #afterReturning(Advice)
* @see #afterThrowing(Advice)
*/
protected void after(Advice advice) throws Throwable {
}

/**
* 方法调用抛出异常后通知
*
Expand Down Expand Up @@ -101,6 +111,26 @@ protected void afterCallReturning(Advice advice,

}

/**
* 目标方法调用结束之后,无论正常返回还是抛出异常
* <p>
* 在一个方法调用过程中会调用其他的方法,CALL系列的事件就是来描述这一类调用的情况。
* CALL系列事件必定是包含在BEFORE/RETURN/THROWS事件之间。
* </p>
*
* @param advice Caller的行为通知
* @param callLineNum 调用发生的代码行(可能为-1,取决于目标编译代码的编译策略)
* @param callJavaClassName 调用目标类名
* @param callJavaMethodName 调用目标行为名称
* @param callJavaMethodDesc 调用目标行为描述
* @param callThrowJavaClassName 调用目标异常类名,若正常返回则为 null
*/
protected void afterCall(Advice advice,
int callLineNum,
String callJavaClassName,
String callJavaMethodName, String callJavaMethodDesc, String callThrowJavaClassName) {
}

/**
* 目标方法调用异常之后
* <p>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.alibaba.jvm.sandbox.api.listener.ext;

import java.lang.annotation.Annotation;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
Expand Down Expand Up @@ -37,6 +38,13 @@ Object invoke(Object obj, Object... args)

Annotation[] getDeclaredAnnotations();

/**
* 获取被封装的目标对象: Method/Constructor
*
* @return 目标对象
*/
AccessibleObject getTarget();

/**
* 类实现
*/
Expand Down Expand Up @@ -104,6 +112,11 @@ public Annotation[] getDeclaredAnnotations() {
return target.getDeclaredAnnotations();
}

@Override
public AccessibleObject getTarget() {
return target;
}

@Override
public int hashCode() {
return target.hashCode();
Expand Down Expand Up @@ -183,6 +196,11 @@ public Annotation[] getDeclaredAnnotations() {
return target.getDeclaredAnnotations();
}

@Override
public AccessibleObject getTarget() {
return target;
}

@Override
public int hashCode() {
return target.hashCode();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
* Created by luanjia@taobao.com on 2017/2/7.
*/
public class ModuleHttpServlet extends HttpServlet {

private static final String SLASH = "/";
private final Logger logger = LoggerFactory.getLogger(getClass());

private final CoreModuleManager coreModuleManager;
Expand Down Expand Up @@ -179,29 +179,39 @@ private Method matchingModuleMethod(final String path,
if (null == commandAnnotation) {
continue;
}
final String pathOfCmd = "/" + uniqueId + "/" + commandAnnotation.value();
// 兼容 value 是否以 / 开头的写法
String cmd = appendSlash(commandAnnotation.value());
final String pathOfCmd = "/" + uniqueId + cmd;
if (StringUtils.equals(path, pathOfCmd)) {
return method;
}
}

// 查找@Http注解的方法
for (final Method method : MethodUtils.getMethodsListWithAnnotation(classOfModule, Http.class)) {
final Http httpAnnotation = method.getAnnotation(Http.class);
if (null == httpAnnotation) {
continue;
}
final String pathPattern = "/" + uniqueId + httpAnnotation.value();
// 兼容 value 是否以 / 开头的写法
String cmd = appendSlash(httpAnnotation.value());
final String pathPattern = "/" + uniqueId + cmd;
if (ArrayUtils.contains(httpAnnotation.method(), httpMethod)
&& matching(path, pathPattern)) {
return method;
}
}

// 找不到匹配方法,返回null
return null;
}

private String appendSlash(String cmd) {
// 若不以 / 开头,则添加 /
if (!cmd.startsWith(SLASH)) {
cmd = SLASH + cmd;
}
return cmd;
}

private boolean isMapWithGenericParameterTypes(final Method method,
final int parameterIndex,
final Class<?> keyClass,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import static com.alibaba.jvm.sandbox.api.util.GaStringUtils.getJavaClassNameArray;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import static org.apache.commons.lang3.ArrayUtils.getLength;
import static java.util.Arrays.deepEquals;

public class InterfaceProxyUtils {

Expand Down Expand Up @@ -46,20 +46,6 @@ String getInterfaceMethodName(final Method interfaceMethod) {
: proxyMethod.name();
}

boolean isEquals(final String[] srcStringArray,
final String[] dstStringArray) {
final int length;
if ((length = getLength(srcStringArray)) != getLength(dstStringArray)) {
return false;
}
for (int index = 0; index < length; index++) {
if (!StringUtils.equals(srcStringArray[index], dstStringArray[index])) {
return false;
}
}
return true;
}

/**
* 比较interfaceMethod和targetMethod两个方法是否接近
*
Expand All @@ -69,8 +55,7 @@ boolean isEquals(final String[] srcStringArray,
*/
boolean isCloseTo(final Method interfaceMethod, final Method targetMethod) {
return StringUtils.equals(getInterfaceMethodName(interfaceMethod), targetMethod.getName())
&& isEquals(getJavaClassNameArray(interfaceMethod.getParameterTypes()), getJavaClassNameArray(targetMethod.getParameterTypes()));

&& deepEquals(getJavaClassNameArray(interfaceMethod.getParameterTypes()), getJavaClassNameArray(targetMethod.getParameterTypes()));
}

Method getTargetMethod(final Method interfaceMethod, final Object target) throws NoSuchMethodException {
Expand Down

0 comments on commit c749290

Please sign in to comment.