diff --git a/CHANGELOG.md b/CHANGELOG.md index faec6d294..3d19d7b27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ * 【core 】 修改StrUtil.equals逻辑,改为contentEquals * 【core 】 增加URLUtil.UrlDecoder * 【core 】 增加XmlUtil.setNamespaceAware,getByPath支持UniversalNamespaceCache +* 【core 】 增加XmlUtil.setNamespaceAware,getByPath支持UniversalNamespaceCache +* 【aop 】 增加Spring-cglib支持,改为SPI实现 ### Bug修复 * 【json 】 修复解析JSON字符串时配置无法传递问题 diff --git a/hutool-aop/pom.xml b/hutool-aop/pom.xml index 73ba81733..e668a5e55 100644 --- a/hutool-aop/pom.xml +++ b/hutool-aop/pom.xml @@ -19,6 +19,7 @@ 3.3.0 + 5.2.5.RELEASE @@ -34,5 +35,12 @@ compile true + + org.springframework + spring-core + ${spring.version} + compile + true + diff --git a/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java b/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java index a157dd9b6..a4b7ddf02 100644 --- a/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java +++ b/hutool-aop/src/main/java/cn/hutool/aop/interceptor/CglibInterceptor.java @@ -1,6 +1,7 @@ package cn.hutool.aop.interceptor; import cn.hutool.aop.aspects.Aspect; +import cn.hutool.core.lang.Console; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; @@ -42,6 +43,7 @@ public class CglibInterceptor implements MethodInterceptor, Serializable { if (aspect.before(target, method, args)) { try { // result = proxy.invokeSuper(obj, args); + Console.log(target); result = proxy.invoke(target, args); } catch (InvocationTargetException e) { // 异常回调(只捕获业务代码导致的异常,而非反射导致的异常) diff --git a/hutool-aop/src/main/java/cn/hutool/aop/interceptor/SpringCglibInterceptor.java b/hutool-aop/src/main/java/cn/hutool/aop/interceptor/SpringCglibInterceptor.java new file mode 100644 index 000000000..8f3afa390 --- /dev/null +++ b/hutool-aop/src/main/java/cn/hutool/aop/interceptor/SpringCglibInterceptor.java @@ -0,0 +1,65 @@ +package cn.hutool.aop.interceptor; + +import cn.hutool.aop.aspects.Aspect; +import org.springframework.cglib.proxy.MethodInterceptor; +import org.springframework.cglib.proxy.MethodProxy; + +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Spring-cglib实现的动态代理切面 + * + * @author looly + */ +public class SpringCglibInterceptor implements MethodInterceptor, Serializable { + private static final long serialVersionUID = 1L; + + private final Object target; + private final Aspect aspect; + + /** + * 构造 + * + * @param target 被代理对象 + * @param aspect 切面实现 + */ + public SpringCglibInterceptor(Object target, Aspect aspect) { + this.target = target; + this.aspect = aspect; + } + + /** + * 获得目标对象 + * + * @return 目标对象 + */ + public Object getTarget() { + return this.target; + } + + @Override + public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { + final Object target = this.target; + Object result = null; + // 开始前回调 + if (aspect.before(target, method, args)) { + try { +// result = proxy.invokeSuper(obj, args); + result = proxy.invoke(target, args); + } catch (InvocationTargetException e) { + // 异常回调(只捕获业务代码导致的异常,而非反射导致的异常) + if (aspect.afterException(target, method, args, e.getTargetException())) { + throw e; + } + } + } + + // 结束执行回调 + if (aspect.after(target, method, args, result)) { + return result; + } + return null; + } +} diff --git a/hutool-aop/src/main/java/cn/hutool/aop/proxy/ProxyFactory.java b/hutool-aop/src/main/java/cn/hutool/aop/proxy/ProxyFactory.java index 24ac30871..8186ea668 100644 --- a/hutool-aop/src/main/java/cn/hutool/aop/proxy/ProxyFactory.java +++ b/hutool-aop/src/main/java/cn/hutool/aop/proxy/ProxyFactory.java @@ -1,46 +1,59 @@ package cn.hutool.aop.proxy; -import java.io.Serializable; - import cn.hutool.aop.aspects.Aspect; import cn.hutool.core.util.ReflectUtil; +import cn.hutool.core.util.ServiceLoaderUtil; + +import java.io.Serializable; /** * 代理工厂
* 根据用户引入代理库的不同,产生不同的代理对象 - * - * @author looly * + * @author looly */ -public abstract class ProxyFactory implements Serializable{ +public abstract class ProxyFactory implements Serializable { private static final long serialVersionUID = 1L; /** * 创建代理 * - * @param 代理对象类型 + * @param 代理对象类型 + * @param target 被代理对象 + * @param aspectClass 切面实现类,自动实例化 + * @return 代理对象 + * @since 5.3.1 + */ + public T proxy(T target, Class aspectClass) { + return proxy(target, ReflectUtil.newInstanceIfPossible(aspectClass)); + } + + /** + * 创建代理 + * + * @param 代理对象类型 * @param target 被代理对象 * @param aspect 切面实现 * @return 代理对象 */ public abstract T proxy(T target, Aspect aspect); - + /** * 根据用户引入Cglib与否自动创建代理对象 - * - * @param 切面对象类型 - * @param target 目标对象 + * + * @param 切面对象类型 + * @param target 目标对象 * @param aspectClass 切面对象类 * @return 代理对象 */ - public static T createProxy(T target, Class aspectClass){ + public static T createProxy(T target, Class aspectClass) { return createProxy(target, ReflectUtil.newInstance(aspectClass)); } /** * 根据用户引入Cglib与否自动创建代理对象 - * - * @param 切面对象类型 + * + * @param 切面对象类型 * @param target 被代理对象 * @param aspect 切面实现 * @return 代理对象 @@ -51,15 +64,10 @@ public abstract class ProxyFactory implements Serializable{ /** * 根据用户引入Cglib与否创建代理工厂 - * + * * @return 代理工厂 */ public static ProxyFactory create() { - try { - return new CglibProxyFactory(); - } catch (NoClassDefFoundError e) { - // ignore - } - return new JdkProxyFactory(); + return ServiceLoaderUtil.loadFirstAvailable(ProxyFactory.class); } } diff --git a/hutool-aop/src/main/java/cn/hutool/aop/proxy/SpringCglibProxyFactory.java b/hutool-aop/src/main/java/cn/hutool/aop/proxy/SpringCglibProxyFactory.java new file mode 100644 index 000000000..46db19996 --- /dev/null +++ b/hutool-aop/src/main/java/cn/hutool/aop/proxy/SpringCglibProxyFactory.java @@ -0,0 +1,25 @@ +package cn.hutool.aop.proxy; + +import cn.hutool.aop.aspects.Aspect; +import cn.hutool.aop.interceptor.SpringCglibInterceptor; +import org.springframework.cglib.proxy.Enhancer; + +/** + * 基于Spring-cglib的切面代理工厂 + * + * @author looly + * + */ +public class SpringCglibProxyFactory extends ProxyFactory{ + private static final long serialVersionUID = 1L; + + @Override + @SuppressWarnings("unchecked") + public T proxy(T target, Aspect aspect) { + final Enhancer enhancer = new Enhancer(); + enhancer.setSuperclass(target.getClass()); + enhancer.setCallback(new SpringCglibInterceptor(target, aspect)); + return (T) enhancer.create(); + } + +} diff --git a/hutool-aop/src/main/resources/META-INF/services/cn.hutool.aop.proxy.ProxyFactory b/hutool-aop/src/main/resources/META-INF/services/cn.hutool.aop.proxy.ProxyFactory new file mode 100644 index 000000000..2bad43826 --- /dev/null +++ b/hutool-aop/src/main/resources/META-INF/services/cn.hutool.aop.proxy.ProxyFactory @@ -0,0 +1,3 @@ +cn.hutool.aop.proxy.CglibProxyFactory +cn.hutool.aop.proxy.SpringCglibProxyFactory +cn.hutool.aop.proxy.JdkProxyFactory \ No newline at end of file diff --git a/hutool-aop/src/test/java/cn/hutool/aop/test/AopTest.java b/hutool-aop/src/test/java/cn/hutool/aop/test/AopTest.java index eb036d1d4..55da3d3e7 100644 --- a/hutool-aop/src/test/java/cn/hutool/aop/test/AopTest.java +++ b/hutool-aop/src/test/java/cn/hutool/aop/test/AopTest.java @@ -23,7 +23,7 @@ public class AopTest { } @Test - public void aopByCglibTest() { + public void aopByAutoCglibTest() { Dog dog = ProxyUtil.proxy(new Dog(), TimeIntervalAspect.class); String result = dog.eat(); Assert.assertEquals("狗吃肉", result);