feat: 彻底解耦reflections

This commit is contained in:
wangyu 2024-07-01 16:53:22 +08:00
parent 274febda39
commit 7fcd7c6e02
9 changed files with 88 additions and 103 deletions

View File

@ -13,7 +13,11 @@ import org.springframework.util.CollectionUtils;
import java.io.IOException; import java.io.IOException;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.util.*; import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Stream;
/** /**
* 内部的包扫描器提供特定注解扫描 * 内部的包扫描器提供特定注解扫描
@ -61,6 +65,13 @@ public class ClassPathResourceScanner extends ClassPathScanningCandidateComponen
return true; return true;
} }
/**
* 解析具体类型
*
* @param bf bean定义
* @param cl 类加载器
* @return 结果
*/
private Class<?> resolveType(BeanDefinition bf, ClassLoader cl) { private Class<?> resolveType(BeanDefinition bf, ClassLoader cl) {
if (null != bf.getBeanClassName()) { if (null != bf.getBeanClassName()) {
try { try {
@ -78,23 +89,19 @@ public class ClassPathResourceScanner extends ClassPathScanningCandidateComponen
* @param packageNames 包名 * @param packageNames 包名
* @return 结果 * @return 结果
*/ */
public Set<Class<?>> scan(Collection<String> packageNames) { public Stream<Class<?>> scan(Collection<String> packageNames) {
// 获取扫描器的ClassLoader保证同源 // 获取扫描器的ClassLoader保证同源
ClassLoader cl = this.getClass().getClassLoader(); ClassLoader cl = this.getClass().getClassLoader();
Set<Class<?>> scanned = new HashSet<>(); Stream<Class<?>> stream = packageNames.stream()
for (String packageName : packageNames) { .flatMap(packageName -> {
Set<BeanDefinition> bfs = findCandidateComponents(packageName); Set<BeanDefinition> bfs = findCandidateComponents(packageName);
// 不存在不要浪费性能 // 不存在不要浪费性能
if (CollectionUtils.isEmpty(bfs)) continue; if (CollectionUtils.isEmpty(bfs)) return Stream.empty();
// 代理并生成子类并注册到ioc容器 // 代理并生成子类并注册到ioc容器
for (BeanDefinition bf : bfs) { return bfs.stream().map(bf -> resolveType(bf, cl)).filter(Objects::nonNull);
Class<?> resolved = resolveType(bf, cl); });
if (null != resolved) { // 额外返回以保证类型正确
scanned.add(resolved); return stream.distinct();
}
}
}
return scanned;
} }
/** /**
@ -103,7 +110,7 @@ public class ClassPathResourceScanner extends ClassPathScanningCandidateComponen
* @param packageNames 包名 * @param packageNames 包名
* @return 结果 * @return 结果
*/ */
public Set<Class<?>> scan(String... packageNames) { public Stream<Class<?>> scan(String... packageNames) {
return scan(Arrays.asList(packageNames)); return scan(Arrays.asList(packageNames));
} }
} }

View File

@ -25,9 +25,10 @@ public class EnumConfig implements InitializingBean, ImportBeanDefinitionRegistr
public EnumConfig() { public EnumConfig() {
// 得到枚举类 // 得到枚举类
Set<Class<?>> classSet = ClassPathResourceScanner.forSuperType(NamedEnum.class).scan("com.flyfish.project"); ClassPathResourceScanner.forSuperType(NamedEnum.class)
// 注入 .scan("com.flyfish.project")
classSet.stream().filter(clazz -> ClassUtils.isAssignable(clazz, Enum.class)).forEach(clazz -> { .filter(clazz -> ClassUtils.isAssignable(clazz, Enum.class))
.forEach(clazz -> {
String name = StringFormats.camel2Line(clazz.getSimpleName()); String name = StringFormats.camel2Line(clazz.getSimpleName());
List<EnumValue> values = Arrays.stream(clazz.getEnumConstants()).reduce(new ArrayList<>(), (result, item) -> { List<EnumValue> values = Arrays.stream(clazz.getEnumConstants()).reduce(new ArrayList<>(), (result, item) -> {
result.add(new EnumValue(((Enum<?>) item).name(), ((NamedEnum) item).getName())); result.add(new EnumValue(((Enum<?>) item).name(), ((NamedEnum) item).getName()));

View File

@ -34,9 +34,5 @@
<version>${revision}</version> <version>${revision}</version>
<optional>true</optional> <optional>true</optional>
</dependency> </dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -4,29 +4,25 @@ import com.flyfish.framework.annotations.DictValue;
import com.flyfish.framework.dict.domain.Dictionary; import com.flyfish.framework.dict.domain.Dictionary;
import com.flyfish.framework.dict.domain.DictionaryValue; import com.flyfish.framework.dict.domain.DictionaryValue;
import com.flyfish.framework.dict.service.DictionaryService; import com.flyfish.framework.dict.service.DictionaryService;
import com.flyfish.framework.domain.base.Domain;
import com.flyfish.framework.enums.BlankEnum; import com.flyfish.framework.enums.BlankEnum;
import com.flyfish.framework.enums.NamedEnum; import com.flyfish.framework.enums.NamedEnum;
import com.flyfish.framework.utils.Assert; import com.flyfish.framework.utils.Assert;
import com.flyfish.framework.utils.ClassPathResourceScanner;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.reflections.Reflections; import org.apache.commons.lang3.reflect.FieldUtils;
import org.reflections.scanners.Scanners;
import org.reflections.util.ClasspathHelper;
import org.reflections.util.ConfigurationBuilder;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux; import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream;
/** /**
* 字典处理器 * 字典处理器
@ -45,17 +41,14 @@ public class DictionaryProcessor implements InitializingBean {
public void afterPropertiesSet() { public void afterPropertiesSet() {
String[] basePackages = DictionaryConfig.basePackages(); String[] basePackages = DictionaryConfig.basePackages();
Assert.notNull(basePackages, "未指定明确的字典扫描路径!"); Assert.notNull(basePackages, "未指定明确的字典扫描路径!");
Collection<URL> urls = Arrays.stream(basePackages).flatMap(pack -> ClasspathHelper.forPackage(pack).stream()) Stream<DictValue> annotations = ClassPathResourceScanner.forSuperType(Domain.class)
.collect(Collectors.toList()); .scan(basePackages)
Reflections reflections = new Reflections(new ConfigurationBuilder() .flatMap(clazz -> Arrays.stream(FieldUtils.getFieldsWithAnnotation(clazz, DictValue.class)))
.setUrls(urls)
.setScanners(Scanners.FieldsAnnotated));
Set<Field> fields = reflections.getFieldsAnnotatedWith(DictValue.class);
if (CollectionUtils.isNotEmpty(fields)) {
Flux.fromIterable(fields)
.map(field -> field.getAnnotation(DictValue.class)) .map(field -> field.getAnnotation(DictValue.class))
.filter(annotation -> null != annotation && StringUtils.isNotBlank(annotation.value()) && .filter(annotation -> null != annotation && StringUtils.isNotBlank(annotation.value()) &&
BlankEnum.class != annotation.enumType()) BlankEnum.class != annotation.enumType());
// 查找并更新
Flux.fromStream(annotations)
.distinct(DictValue::enumType) .distinct(DictValue::enumType)
// 查找是否存在不存在插入存在无视 // 查找是否存在不存在插入存在无视
.flatMap(annotation -> dictionaryService .flatMap(annotation -> dictionaryService
@ -67,7 +60,6 @@ public class DictionaryProcessor implements InitializingBean {
.flatMapMany(dictionaryService::updateBatch) .flatMapMany(dictionaryService::updateBatch)
.subscribe(); .subscribe();
} }
}
/** /**
* 给字典属性赋值 * 给字典属性赋值

View File

@ -132,24 +132,18 @@ public class WebSecurityConfig {
ReactiveAuthenticationManager authenticationManager = new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService); ReactiveAuthenticationManager authenticationManager = new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService);
return http return http
.securityContextRepository(contextRepository()) .securityContextRepository(contextRepository())
.authorizeExchange() .authorizeExchange(spec -> spec.pathMatchers(ArrayUtils.addAll(properties.getAllowUris(), "/api/logout", "/api/login")).permitAll()
.pathMatchers(ArrayUtils.addAll(properties.getAllowUris(), "/api/logout", "/api/login")).permitAll()
.pathMatchers("/api/users/**").authenticated() .pathMatchers("/api/users/**").authenticated()
.anyExchange().authenticated() .anyExchange().authenticated())
.and() .formLogin(spec -> spec.disable()) // 配置登录节点
.formLogin() // 配置登录节点 .httpBasic(spec -> spec.disable())
.disable() .logout(spec -> spec
.httpBasic()
.disable()
.logout()
.logoutUrl("/api/logout") .logoutUrl("/api/logout")
.logoutSuccessHandler(new JsonLogoutSuccessHandler(authenticationAuditor, tokenProvider)) .logoutSuccessHandler(new JsonLogoutSuccessHandler(authenticationAuditor, tokenProvider)))
.and() .exceptionHandling(spec -> spec
.exceptionHandling()
.authenticationEntryPoint(new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED)) .authenticationEntryPoint(new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED))
.accessDeniedHandler(new HttpStatusServerAccessDeniedHandler(HttpStatus.UNAUTHORIZED)) .accessDeniedHandler(new HttpStatusServerAccessDeniedHandler(HttpStatus.UNAUTHORIZED)))
.and() .csrf(spec -> spec.disable())
.csrf().disable()
.addFilterAt( .addFilterAt(
configure(authenticationManager, authenticationAuditor, authenticationConverter), configure(authenticationManager, authenticationAuditor, authenticationConverter),
SecurityWebFiltersOrder.FORM_LOGIN) SecurityWebFiltersOrder.FORM_LOGIN)

View File

@ -84,7 +84,7 @@ public class RestBeanAutoConfigure implements ImportBeanDefinitionRegistrar, Res
// 寻找基本包路径 // 寻找基本包路径
String basePackage = basePackages.stream().findFirst().orElse("com.flyfish.project"); String basePackage = basePackages.stream().findFirst().orElse("com.flyfish.project");
// 获取被注解的类开始编译 // 获取被注解的类开始编译
Set<Class<?>> classes = ClassPathResourceScanner.forAnnotation(RestBean.class).scan(basePackages); Stream<Class<?>> classes = ClassPathResourceScanner.forAnnotation(RestBean.class).scan(basePackages);
// 并发编译快速接入准备注册的repo // 并发编译快速接入准备注册的repo
Map<RestBeanCandidate, List<String>> compiledClasses = compile(basePackage, classes); Map<RestBeanCandidate, List<String>> compiledClasses = compile(basePackage, classes);
// 从repo开始注册bean // 从repo开始注册bean
@ -110,7 +110,7 @@ public class RestBeanAutoConfigure implements ImportBeanDefinitionRegistrar, Res
* @param classes 类集合 * @param classes 类集合
* @return 结果 * @return 结果
*/ */
private Map<RestBeanCandidate, List<String>> compile(String basePackage, Set<Class<?>> classes) { private Map<RestBeanCandidate, List<String>> compile(String basePackage, Stream<Class<?>> classes) {
Map<RestBeanCandidate, List<String>> compiled = new ConcurrentHashMap<>(); Map<RestBeanCandidate, List<String>> compiled = new ConcurrentHashMap<>();
classes.forEach(clazz -> { classes.forEach(clazz -> {
RestBean restBean = clazz.getDeclaredAnnotation(RestBean.class); RestBean restBean = clazz.getDeclaredAnnotation(RestBean.class);

View File

@ -8,12 +8,11 @@ import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
public class JacksonRedisSerializerFactory { public class JacksonRedisSerializerFactory {
public static Jackson2JsonRedisSerializer<Object> produce() { public static Jackson2JsonRedisSerializer<Object> produce() {
// 设置序列化 // 构造object mapper
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper(); ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om); // 设置序列化
return jackson2JsonRedisSerializer; return new Jackson2JsonRedisSerializer<Object>(om, Object.class);
} }
} }

View File

@ -30,9 +30,11 @@ public class EnumController {
private final Map<String, List<EnumValue>> values = new HashMap<>(); private final Map<String, List<EnumValue>> values = new HashMap<>();
public EnumController() { public EnumController() {
Set<Class<?>> classSet = ClassPathResourceScanner.forSuperType(NamedEnum.class).scan("com.flyfish.project", "com.flyfish.framework");
// 注入 // 注入
classSet.stream().filter(clazz -> ClassUtils.isAssignable(clazz, Enum.class)).forEach(clazz -> { ClassPathResourceScanner.forSuperType(NamedEnum.class)
.scan("com.flyfish.project", "com.flyfish.framework")
.filter(clazz -> ClassUtils.isAssignable(clazz, Enum.class))
.forEach(clazz -> {
String name = StringFormats.camel2Line(ClassUtils.getShortClassName(clazz)); String name = StringFormats.camel2Line(ClassUtils.getShortClassName(clazz));
List<EnumValue> values = Arrays.stream(clazz.getEnumConstants()).reduce(new ArrayList<>(), (result, item) -> { List<EnumValue> values = Arrays.stream(clazz.getEnumConstants()).reduce(new ArrayList<>(), (result, item) -> {
result.add(new EnumValue(((Enum<?>) item).name(), ((NamedEnum) item).getName())); result.add(new EnumValue(((Enum<?>) item).name(), ((NamedEnum) item).getName()));

View File

@ -25,7 +25,6 @@
<java.version>17</java.version> <java.version>17</java.version>
<jasypt.version>3.1.0</jasypt.version> <jasypt.version>3.1.0</jasypt.version>
<jjwt.version>0.12.6</jjwt.version> <jjwt.version>0.12.6</jjwt.version>
<reflection.version>0.10.2</reflection.version>
<r2dbc-mysql.version>1.1.3</r2dbc-mysql.version> <r2dbc-mysql.version>1.1.3</r2dbc-mysql.version>
<flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version> <flatten-maven-plugin.version>1.5.0</flatten-maven-plugin.version>
<captcha.version>1.3.0</captcha.version> <captcha.version>1.3.0</captcha.version>
@ -112,11 +111,6 @@
<artifactId>commons-io</artifactId> <artifactId>commons-io</artifactId>
<version>2.16.1</version> <version>2.16.1</version>
</dependency> </dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>${reflection.version}</version>
</dependency>
<dependency> <dependency>
<groupId>io.springboot.plugin</groupId> <groupId>io.springboot.plugin</groupId>
<artifactId>jasypt-spring-boot-starter</artifactId> <artifactId>jasypt-spring-boot-starter</artifactId>