Commit 45cda665 authored by ma yanling's avatar ma yanling
Browse files

project commit

parent ad2fb30a
Pipeline #2354 failed with stages
in 0 seconds
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;
}
}
/**
* 代理拦截器实现
*
* @author looly
*
*/
package cn.hutool.aop.interceptor;
\ No newline at end of file
/**
* JDK动态代理封装,提供非IOC下的切面支持
*
* @author looly
*
*/
package cn.hutool.aop;
\ No newline at end of file
package cn.hutool.aop.proxy;
import cn.hutool.aop.aspects.Aspect;
import cn.hutool.aop.interceptor.CglibInterceptor;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import net.sf.cglib.proxy.Enhancer;
import java.lang.reflect.Constructor;
/**
* 基于Cglib的切面代理工厂
*
* @author looly
*
*/
public class CglibProxyFactory extends ProxyFactory{
private static final long serialVersionUID = 1L;
@Override
public <T> T proxy(T target, Aspect aspect) {
final Class<?> targetClass = target.getClass();
final Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(new CglibInterceptor(target, aspect));
return create(enhancer, targetClass);
}
/**
* 创建代理对象<br>
* https://gitee.com/dromara/hutool/issues/I74EX7<br>
* 某些对象存在非空参数构造,则需遍历查找需要的构造完成代理对象构建。
*
* @param <T> 代理对象类型
* @param enhancer {@link org.springframework.cglib.proxy.Enhancer}
* @param targetClass 目标类型
* @return 代理对象
*/
@SuppressWarnings("unchecked")
private static <T> T create(final Enhancer enhancer, final Class<?> targetClass) {
final Constructor<?>[] constructors = ReflectUtil.getConstructors(targetClass);
Class<?>[] parameterTypes;
Object[] values;
IllegalArgumentException finalException = null;
for (final Constructor<?> constructor : constructors) {
parameterTypes = constructor.getParameterTypes();
values = ClassUtil.getDefaultValues(parameterTypes);
try {
return (T) enhancer.create(parameterTypes, values);
} catch (final IllegalArgumentException e) {
//ignore
finalException = e;
}
}
if (null != finalException) {
throw finalException;
}
throw new IllegalArgumentException("No constructor provided");
}
}
package cn.hutool.aop.proxy;
import cn.hutool.aop.ProxyUtil;
import cn.hutool.aop.aspects.Aspect;
import cn.hutool.aop.interceptor.JdkInterceptor;
/**
* JDK实现的切面代理
*
* @author looly
*/
public class JdkProxyFactory extends ProxyFactory {
private static final long serialVersionUID = 1L;
@Override
public <T> T proxy(T target, Aspect aspect) {
return ProxyUtil.newProxyInstance(//
target.getClass().getClassLoader(), //
new JdkInterceptor(target, aspect), //
target.getClass().getInterfaces());
}
}
package cn.hutool.aop.proxy;
import cn.hutool.aop.aspects.Aspect;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.ServiceLoaderUtil;
import java.io.Serializable;
/**
* 代理工厂<br>
* 根据用户引入代理库的不同,产生不同的代理对象
*
* @author looly
*/
public abstract class ProxyFactory implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 创建代理
*
* @param <T> 代理对象类型
* @param target 被代理对象
* @param aspectClass 切面实现类,自动实例化
* @return 代理对象
* @since 5.3.1
*/
public <T> T proxy(T target, Class<? extends Aspect> aspectClass) {
return proxy(target, ReflectUtil.newInstanceIfPossible(aspectClass));
}
/**
* 创建代理
*
* @param <T> 代理对象类型
* @param target 被代理对象
* @param aspect 切面实现
* @return 代理对象
*/
public abstract <T> T proxy(T target, Aspect aspect);
/**
* 根据用户引入Cglib与否自动创建代理对象
*
* @param <T> 切面对象类型
* @param target 目标对象
* @param aspectClass 切面对象类
* @return 代理对象
*/
public static <T> T createProxy(T target, Class<? extends Aspect> aspectClass) {
return createProxy(target, ReflectUtil.newInstance(aspectClass));
}
/**
* 根据用户引入Cglib与否自动创建代理对象
*
* @param <T> 切面对象类型
* @param target 被代理对象
* @param aspect 切面实现
* @return 代理对象
*/
public static <T> T createProxy(T target, Aspect aspect) {
return create().proxy(target, aspect);
}
/**
* 根据用户引入Cglib与否创建代理工厂
*
* @return 代理工厂
*/
public static ProxyFactory create() {
return ServiceLoaderUtil.loadFirstAvailable(ProxyFactory.class);
}
}
package cn.hutool.aop.proxy;
import cn.hutool.aop.aspects.Aspect;
import cn.hutool.aop.interceptor.SpringCglibInterceptor;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.ReflectUtil;
import org.springframework.cglib.proxy.Enhancer;
import java.lang.reflect.Constructor;
/**
* 基于Spring-cglib的切面代理工厂
*
* @author looly
*
*/
public class SpringCglibProxyFactory extends ProxyFactory{
private static final long serialVersionUID = 1L;
@Override
public <T> T proxy(T target, Aspect aspect) {
final Class<?> targetClass = target.getClass();
final Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new SpringCglibInterceptor(target, aspect));
return create(enhancer, targetClass);
}
/**
* 创建代理对象<br>
* https://gitee.com/dromara/hutool/issues/I74EX7<br>
* 某些对象存在非空参数构造,则需遍历查找需要的构造完成代理对象构建。
*
* @param <T> 代理对象类型
* @param enhancer {@link Enhancer}
* @param targetClass 目标类型
* @return 代理对象
*/
@SuppressWarnings("unchecked")
private static <T> T create(final Enhancer enhancer, final Class<?> targetClass) {
final Constructor<?>[] constructors = ReflectUtil.getConstructors(targetClass);
Class<?>[] parameterTypes;
Object[] values;
IllegalArgumentException finalException = null;
for (final Constructor<?> constructor : constructors) {
parameterTypes = constructor.getParameterTypes();
values = ClassUtil.getDefaultValues(parameterTypes);
try {
return (T) enhancer.create(parameterTypes, values);
} catch (final IllegalArgumentException e) {
//ignore
finalException = e;
}
}
if (null != finalException) {
throw finalException;
}
throw new IllegalArgumentException("No constructor provided");
}
}
/**
* 代理实现
*
* @author looly
*
*/
package cn.hutool.aop.proxy;
\ No newline at end of file
cn.hutool.aop.proxy.CglibProxyFactory
cn.hutool.aop.proxy.SpringCglibProxyFactory
cn.hutool.aop.proxy.JdkProxyFactory
\ No newline at end of file
package cn.hutool.aop.test;
import cn.hutool.aop.ProxyUtil;
import cn.hutool.aop.aspects.TimeIntervalAspect;
import cn.hutool.core.lang.Console;
import lombok.Data;
import org.junit.Assert;
import org.junit.Test;
/**
* AOP模块单元测试
*
* @author Looly
*/
public class AopTest {
@Test
public void aopTest() {
Animal cat = ProxyUtil.proxy(new Cat(), TimeIntervalAspect.class);
String result = cat.eat();
Assert.assertEquals("猫吃鱼", result);
cat.seize();
}
@Test
public void aopByAutoCglibTest() {
Dog dog = ProxyUtil.proxy(new Dog(), TimeIntervalAspect.class);
String result = dog.eat();
Assert.assertEquals("狗吃肉", result);
dog.seize();
}
interface Animal {
String eat();
void seize();
}
/**
* 有接口
*
* @author looly
*/
static class Cat implements Animal {
@Override
public String eat() {
return "猫吃鱼";
}
@Override
public void seize() {
Console.log("抓了条鱼");
}
}
/**
* 无接口
*
* @author looly
*/
static class Dog {
public String eat() {
return "狗吃肉";
}
public void seize() {
Console.log("抓了只鸡");
}
}
@Test
public void testCGLIBProxy() {
TagObj target = new TagObj();
//目标类设置标记
target.setTag("tag");
TagObj proxy = ProxyUtil.proxy(target, TimeIntervalAspect.class);
//代理类获取标记tag (断言错误)
Assert.assertEquals("tag", proxy.getTag());
}
@Data
public static class TagObj{
private String tag;
}
}
/*
* Copyright (c) 2023 looly(loolly@aliyun.com)
* Hutool is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package cn.hutool.aop.test;
import cn.hutool.aop.aspects.SimpleAspect;
import cn.hutool.aop.proxy.CglibProxyFactory;
import cn.hutool.aop.proxy.JdkProxyFactory;
import cn.hutool.aop.proxy.ProxyFactory;
import cn.hutool.aop.proxy.SpringCglibProxyFactory;
import cn.hutool.core.lang.Console;
import lombok.Setter;
import org.junit.Test;
public class IssueI74EX7Test {
@Test
public void proxyTest() {
final SmsBlend smsBlend = new SmsBlendImpl(1);
final ProxyFactory engine = new JdkProxyFactory();
engine.proxy(smsBlend, new SimpleAspect());
}
/**
* https://gitee.com/dromara/hutool/issues/I74EX7<br>
* Enhancer.create()默认调用无参构造,有参构造或者多个构造没有很好的兼容。
*
*/
@Test
public void cglibProxyTest() {
final SmsBlend smsBlend = new SmsBlendImpl(1);
final ProxyFactory engine = new CglibProxyFactory();
engine.proxy(smsBlend, new SimpleAspect());
}
/**
* https://gitee.com/dromara/hutool/issues/I74EX7<br>
* Enhancer.create()默认调用无参构造,有参构造或者多个构造没有很好的兼容。
*
*/
@Test
public void springCglibProxyTest() {
final SmsBlend smsBlend = new SmsBlendImpl(1);
final ProxyFactory engine = new SpringCglibProxyFactory();
engine.proxy(smsBlend, new SimpleAspect());
}
@Test
public void springCglibProxyWithoutConstructorTest() {
final SmsBlend smsBlend = new SmsBlendImplWithoutConstructor();
final ProxyFactory engine = new SpringCglibProxyFactory();
engine.proxy(smsBlend, new SimpleAspect());
}
public interface SmsBlend{
void send();
}
public static class SmsBlendImpl implements SmsBlend{
private final int status;
public SmsBlendImpl(final int status) {
this.status = status;
}
@Override
public void send() {
Console.log("sms send." + status);
}
}
@Setter
public static class SmsBlendImplWithoutConstructor implements SmsBlend{
private int status;
@Override
public void send() {
Console.log("sms send." + status);
}
}
}
<?xml version='1.0' encoding='utf-8'?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<parent>
<groupId>cn.hutool</groupId>
<artifactId>hutool-parent</artifactId>
<version>5.8.19</version>
</parent>
<artifactId>hutool-bloomFilter</artifactId>
<name>${project.artifactId}</name>
<description>Hutool 布隆过滤器</description>
<properties>
<Automatic-Module-Name>cn.hutool.bloomfilter</Automatic-Module-Name>
</properties>
<dependencies>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>
package cn.hutool.bloomfilter;
import cn.hutool.bloomfilter.filter.DefaultFilter;
import cn.hutool.bloomfilter.filter.ELFFilter;
import cn.hutool.bloomfilter.filter.JSFilter;
import cn.hutool.bloomfilter.filter.PJWFilter;
import cn.hutool.bloomfilter.filter.SDBMFilter;
import cn.hutool.core.util.NumberUtil;
/**
* BloomFilter 实现 <br>
* 1.构建hash算法 <br>
* 2.散列hash映射到数组的bit位置 <br>
* 3.验证<br>
* 此实现方式可以指定Hash算法
*
* @author Ansj
*/
public class BitMapBloomFilter implements BloomFilter {
private static final long serialVersionUID = 1L;
private BloomFilter[] filters;
/**
* 构造,使用默认的5个过滤器
*
* @param m M值决定BitMap的大小
*/
public BitMapBloomFilter(int m) {
long mNum = NumberUtil.div(String.valueOf(m), String.valueOf(5)).longValue();
long size = mNum * 1024 * 1024 * 8;
filters = new BloomFilter[]{
new DefaultFilter(size),
new ELFFilter(size),
new JSFilter(size),
new PJWFilter(size),
new SDBMFilter(size)
};
}
/**
* 使用自定的多个过滤器建立BloomFilter
*
* @param m M值决定BitMap的大小
* @param filters Bloom过滤器列表
*/
public BitMapBloomFilter(int m, BloomFilter... filters) {
this(m);
this.filters = filters;
}
/**
* 增加字符串到Filter映射中
*
* @param str 字符串
*/
@Override
public boolean add(String str) {
boolean flag = false;
for (BloomFilter filter : filters) {
flag |= filter.add(str);
}
return flag;
}
/**
* 是否可能包含此字符串,此处存在误判
*
* @param str 字符串
* @return 是否存在
*/
@Override
public boolean contains(String str) {
for (BloomFilter filter : filters) {
if (filter.contains(str) == false) {
return false;
}
}
return true;
}
}
package cn.hutool.bloomfilter;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.HashUtil;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.BitSet;
/**
* BloomFilter实现方式2,此方式使用BitSet存储。<br>
* Hash算法的使用使用固定顺序,只需指定个数即可
*
* @author loolly
*/
public class BitSetBloomFilter implements BloomFilter {
private static final long serialVersionUID = 1L;
private final BitSet bitSet;
private final int bitSetSize;
private final int addedElements;
private final int hashFunctionNumber;
/**
* 构造一个布隆过滤器,过滤器的容量为c * n 个bit.
*
* @param c 当前过滤器预先开辟的最大包含记录,通常要比预计存入的记录多一倍.
* @param n 当前过滤器预计所要包含的记录.
* @param k 哈希函数的个数,等同每条记录要占用的bit数.
*/
public BitSetBloomFilter(int c, int n, int k) {
this.hashFunctionNumber = k;
this.bitSetSize = (int) Math.ceil(c * k);
this.addedElements = n;
this.bitSet = new BitSet(this.bitSetSize);
}
/**
* 通过文件初始化过滤器.
*
* @param path 文件路径
* @param charsetName 字符集
* @throws IOException IO异常
* @deprecated 请使用 {@link #init(String, Charset)}
*/
@Deprecated
public void init(String path, String charsetName) throws IOException {
init(path, CharsetUtil.charset(charsetName));
}
/**
* 通过文件初始化过滤器.
*
* @param path 文件路径
* @param charset 字符集
* @throws IOException IO异常
* @since 5.8.0
*/
public void init(String path, Charset charset) throws IOException {
BufferedReader reader = FileUtil.getReader(path, charset);
try {
String line;
while (true) {
line = reader.readLine();
if (line == null) {
break;
}
this.add(line);
}
} finally {
IoUtil.close(reader);
}
}
@Override
public boolean add(String str) {
if (contains(str)) {
return false;
}
int[] positions = createHashes(str, hashFunctionNumber);
for (int value : positions) {
int position = Math.abs(value % bitSetSize);
bitSet.set(position, true);
}
return true;
}
/**
* 判定是否包含指定字符串
*
* @param str 字符串
* @return 是否包含,存在误差
*/
@Override
public boolean contains(String str) {
int[] positions = createHashes(str, hashFunctionNumber);
for (int i : positions) {
int position = Math.abs(i % bitSetSize);
if (!bitSet.get(position)) {
return false;
}
}
return true;
}
/**
* @return 得到当前过滤器的错误率.
*/
public double getFalsePositiveProbability() {
// (1 - e^(-k * n / m)) ^ k
return Math.pow((1 - Math.exp(-hashFunctionNumber * (double) addedElements / bitSetSize)), hashFunctionNumber);
}
/**
* 将字符串的字节表示进行多哈希编码.
*
* @param str 待添加进过滤器的字符串字节表示.
* @param hashNumber 要经过的哈希个数.
* @return 各个哈希的结果数组.
*/
public static int[] createHashes(String str, int hashNumber) {
int[] result = new int[hashNumber];
for (int i = 0; i < hashNumber; i++) {
result[i] = hash(str, i);
}
return result;
}
/**
* 计算Hash值
*
* @param str 被计算Hash的字符串
* @param k Hash算法序号
* @return Hash值
*/
public static int hash(String str, int k) {
switch (k) {
case 0:
return HashUtil.rsHash(str);
case 1:
return HashUtil.jsHash(str);
case 2:
return HashUtil.elfHash(str);
case 3:
return HashUtil.bkdrHash(str);
case 4:
return HashUtil.apHash(str);
case 5:
return HashUtil.djbHash(str);
case 6:
return HashUtil.sdbmHash(str);
case 7:
return HashUtil.pjwHash(str);
default:
return 0;
}
}
}
package cn.hutool.bloomfilter;
import java.io.Serializable;
/**
* Bloom filter 是由 Howard Bloom 在 1970 年提出的二进制向量数据结构,它具有很好的空间和时间效率,被用来检测一个元素是不是集合中的一个成员。<br>
* 如果检测结果为是,该元素不一定在集合中;但如果检测结果为否,该元素一定不在集合中。<br>
* 因此Bloom filter具有100%的召回率。这样每个检测请求返回有“在集合内(可能错误)”和“不在集合内(绝对不在集合内)”两种情况。<br>
* @author Looly
*
*/
public interface BloomFilter extends Serializable{
/**
*
* @param str 字符串
* @return 判断一个字符串是否bitMap中存在
*/
boolean contains(String str);
/**
* 在boolean的bitMap中增加一个字符串<br>
* 如果存在就返回{@code false} .如果不存在.先增加这个字符串.再返回{@code true}
*
* @param str 字符串
* @return 是否加入成功,如果存在就返回{@code false} .如果不存在返回{@code true}
*/
boolean add(String str);
}
package cn.hutool.bloomfilter;
/**
* 布隆过滤器工具
*
* @author looly
* @since 4.1.5
*/
public class BloomFilterUtil {
/**
* 创建一个BitSet实现的布隆过滤器,过滤器的容量为c * n 个bit.
*
* @param c 当前过滤器预先开辟的最大包含记录,通常要比预计存入的记录多一倍.
* @param n 当前过滤器预计所要包含的记录.
* @param k 哈希函数的个数,等同每条记录要占用的bit数.
* @return BitSetBloomFilter
*/
public static BitSetBloomFilter createBitSet(int c, int n, int k) {
return new BitSetBloomFilter(c, n, k);
}
/**
* 创建BitMap实现的布隆过滤器
*
* @param m BitMap的大小
* @return BitMapBloomFilter
*/
public static BitMapBloomFilter createBitMap(int m) {
return new BitMapBloomFilter(m);
}
}
package cn.hutool.bloomfilter.bitMap;
/**
* BitMap接口,用于将某个int或long值映射到一个数组中,从而判定某个值是否存在
*
* @author looly
*
*/
public interface BitMap{
int MACHINE32 = 32;
int MACHINE64 = 64;
/**
* 加入值
*
* @param i 值
*/
void add(long i);
/**
* 检查是否包含值
*
* @param i 值
* @return 是否包含
*/
boolean contains(long i);
/**
* 移除值
*
* @param i 值
*/
void remove(long i);
}
\ No newline at end of file
package cn.hutool.bloomfilter.bitMap;
import java.io.Serializable;
/**
* 过滤器BitMap在32位机器上.这个类能发生更好的效果.一般情况下建议使用此类
*
* @author loolly
*
*/
public class IntMap implements BitMap, Serializable {
private static final long serialVersionUID = 1L;
private final int[] ints;
/**
* 构造
*/
public IntMap() {
ints = new int[93750000];
}
/**
* 构造
*
* @param size 容量
*/
public IntMap(int size) {
ints = new int[size];
}
@Override
public void add(long i) {
int r = (int) (i / BitMap.MACHINE32);
int c = (int) (i & (BitMap.MACHINE32 - 1));
ints[r] = ints[r] | (1 << c);
}
@Override
public boolean contains(long i) {
int r = (int) (i / BitMap.MACHINE32);
int c = (int) (i & (BitMap.MACHINE32 - 1));
return ((ints[r] >>> c) & 1) == 1;
}
@Override
public void remove(long i) {
int r = (int) (i / BitMap.MACHINE32);
int c = (int) (i & (BitMap.MACHINE32 - 1));
ints[r] &= ~(1 << c);
}
}
package cn.hutool.bloomfilter.bitMap;
import java.io.Serializable;
/**
* 过滤器BitMap在64位机器上.这个类能发生更好的效果.一般机器不建议使用
*
* @author loolly
*
*/
public class LongMap implements BitMap, Serializable {
private static final long serialVersionUID = 1L;
private final long[] longs;
/**
* 构造
*/
public LongMap() {
longs = new long[93750000];
}
/**
* 构造
*
* @param size 容量
*/
public LongMap(int size) {
longs = new long[size];
}
@Override
public void add(long i) {
int r = (int) (i / BitMap.MACHINE64);
long c = i & (BitMap.MACHINE64 - 1);
longs[r] = longs[r] | (1L << c);
}
@Override
public boolean contains(long i) {
int r = (int) (i / BitMap.MACHINE64);
long c = i & (BitMap.MACHINE64 - 1);
return ((longs[r] >>> c) & 1) == 1;
}
@Override
public void remove(long i) {
int r = (int) (i / BitMap.MACHINE64);
long c = i & (BitMap.MACHINE64 - 1);
longs[r] &= ~(1L << c);
}
}
/**
* BitMap实现
*
* @author looly
*
*/
package cn.hutool.bloomfilter.bitMap;
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment