diff --git a/src/main/java/byx/aop/AOP.java b/src/main/java/byx/aop/AOP.java index e90ac31..63954b5 100644 --- a/src/main/java/byx/aop/AOP.java +++ b/src/main/java/byx/aop/AOP.java @@ -37,19 +37,35 @@ else if (target.getClass().getInterfaces().length == 0) } /** - * 实现接口 - * @param type 接口类型 + * 动态实现接口 + * @param interfaceType 接口类型 * @param interceptor 方法拦截器 * @param 返回类型 * @return 动态生成的接口实现类 */ - public static T implement(Class type, MethodInterceptor interceptor) + public static T implement(Class interfaceType, MethodInterceptor interceptor) { - return type.cast(Proxy.newProxyInstance(type.getClassLoader(), - new Class[]{type}, + return interfaceType.cast(Proxy.newProxyInstance(interfaceType.getClassLoader(), + new Class[]{interfaceType}, (proxy, method, args) -> interceptor.intercept(MethodSignature.of(method), Invokable.of(method, null), args))); } + /** + * 动态生成子类 + * @param parentType 父类 + * @param interceptor 方法拦截器 + * @param 返回类型 + * @return 动态生成的子类 + */ + public static T extend(Class parentType, MethodInterceptor interceptor) + { + Enhancer enhancer = new Enhancer(); + enhancer.setSuperclass(parentType); + enhancer.setCallback((InvocationHandler) (proxy, method, args) -> + interceptor.intercept(MethodSignature.of(method), Invokable.of(method, null), args)); + return parentType.cast(enhancer.create()); + } + /** * 使用jdk动态代理 */ diff --git a/src/test/java/byx/aop/test/Example5.java b/src/test/java/byx/aop/test/Example5.java index a5aba05..5a50477 100644 --- a/src/test/java/byx/aop/test/Example5.java +++ b/src/test/java/byx/aop/test/Example5.java @@ -10,6 +10,9 @@ import static byx.aop.AOP.proxy; import static byx.aop.core.MethodMatcher.hasAnnotation; +/** + * 参数校验 + */ public class Example5 { @Retention(RetentionPolicy.RUNTIME) @@ -26,45 +29,94 @@ public class Example5 public interface Service { - void login(String username, String password); + String login(String username, String password); } public static class ServiceImpl implements Service { @Validate - public void login(@NotNull String username, @NotNull String password) + public String login(@NotNull String username, @NotNull String password) { System.out.println("正在登录:" + username + " " + password); + return username + " " + password; } } - @Test - public void test() + public static class User { - MethodInterceptor interceptor = (signature, targetMethod, params) -> + private String username; + private String password; + + public String getUsername() + { + return username; + } + + @Validate + public void setUsername(@NotNull String username) + { + System.out.println("username = " + username); + this.username = username; + } + + public String getPassword() { - Annotation[][] parameterAnnotations = signature.getParameterAnnotations(); - for (int i = 0; i < parameterAnnotations.length; ++i) + return password; + } + + @Validate + public void setPassword(@NotNull String password) + { + System.out.println("password = " + password); + this.password = password; + } + } + + // 方法拦截器 + private final MethodInterceptor interceptor = (signature, targetMethod, params) -> + { + Annotation[][] parameterAnnotations = signature.getParameterAnnotations(); + for (int i = 0; i < parameterAnnotations.length; ++i) + { + for (Annotation annotation : parameterAnnotations[i]) { - for (Annotation annotation : parameterAnnotations[i]) + if (annotation instanceof NotNull) { - if (annotation instanceof NotNull) - { - if (params[i] == null) - throw new RuntimeException("第" + (i + 1) + "个参数为null"); - } + if (params[i] == null) + throw new RuntimeException("第" + (i + 1) + "个参数为null"); } } - return targetMethod.invoke(params); - }; + } + return targetMethod.invoke(params); + }; - MethodMatcher matcher = hasAnnotation(Validate.class); + // 方法匹配器 + private final MethodMatcher matcher = hasAnnotation(Validate.class); + @Test + public void test1() + { Service service = proxy(new ServiceImpl(), interceptor.when(matcher)); - service.login("admin", "123456"); + assertEquals("admin 123456", service.login("admin", "123456")); assertThrows(RuntimeException.class, () -> service.login(null, "123456")); assertThrows(RuntimeException.class, () -> service.login("admin", null)); assertThrows(RuntimeException.class, () -> service.login(null, null)); } + + @Test + public void test2() + { + User user = proxy(new User(), interceptor.when(matcher)); + + user.setUsername("XiaoMing"); + assertEquals("XiaoMing", user.getUsername()); + assertThrows(RuntimeException.class, () -> user.setUsername(null)); + assertEquals("XiaoMing", user.getUsername()); + + user.setPassword("123456"); + assertEquals("123456", user.getPassword()); + assertThrows(RuntimeException.class, () -> user.setPassword(null)); + assertEquals("123456", user.getPassword()); + } } diff --git a/src/test/java/byx/aop/test/ExtendTest.java b/src/test/java/byx/aop/test/ExtendTest.java new file mode 100644 index 0000000..f3848d4 --- /dev/null +++ b/src/test/java/byx/aop/test/ExtendTest.java @@ -0,0 +1,71 @@ +package byx.aop.test; + +import byx.aop.exception.NotImplementedException; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +import static byx.aop.AOP.*; +import static byx.aop.core.MethodInterceptor.*; + +public class ExtendTest +{ + public static abstract class User + { + public abstract void setUsername(String username); + public abstract String getUsername(); + public abstract void setPassword(String password); + public abstract String getPassword(); + } + + public static class Student + { + public int getId() + { + return 1001; + } + + public String getName() + { + return "XiaoMing"; + } + } + + @Test + public void test1() + { + User user = extend(User.class, delegateTo(new Object() + { + private String username; + + public void setUsername(String username) + { + this.username = username; + } + + public String getUsername() + { + return username; + } + })); + + user.setUsername("XiaoMing"); + assertEquals("XiaoMing", user.getUsername()); + assertThrows(NotImplementedException.class, () -> user.setPassword("123456")); + assertThrows(NotImplementedException.class, user::getPassword); + } + + @Test + public void test2() + { + Student student = extend(Student.class, delegateTo(new Object() + { + public int getId() + { + return 2002; + } + })); + + assertEquals(2002, student.getId()); + assertThrows(NotImplementedException.class, student::getName); + } +}