转发自动将某个路径下包的文件注入spring 容器中
转发于:https://www.ngui.cc/el/2931198.html?action=onClick
项目中使用策略模式会在spring中获取bean 进行方法调用,使用这个自定义注解后避免创建一个实现添加一个 @Service 注解
一、ClassScanner工具类 (用于加载指定package下的class)
public class ClassScanner {
private final String packageName;
private final String packageUrl;
private final ClassLoader classLoader;
private final Charset charset;
private final Set<Class<?>> classes = new HashSet<>();
public ClassScanner(String packageName, ClassLoader classLoader) {
this.packageName = packageName;
this.classLoader = classLoader;
this.charset = StandardCharsets.UTF_8;
this.packageUrl = packageName.replace(".", File.separator);
}
public ClassScanner(String packageName, ClassLoader classLoader, Charset charset) {
this.packageName = packageName;
this.classLoader = classLoader;
this.charset = charset;
this.packageUrl = packageName.replace(".", File.separator);
}
public Set<Class<?>> scan() {
try {
Enumeration<URL> resources = classLoader.getResources(packageUrl);
EnumerationIter<URL> urls = new EnumerationIter<>(resources);
for (URL url : urls) {
scanFile(new File(URLDecoder.decode(url.getFile(), charset.name())));
}
} catch (IOException e) {
e.printStackTrace();
}
return classes;
}
private void scanFile(File file) {
if (file == null) {
return;
}
if (file.isFile()) {
final String fileName = file.getName();
if (fileName.endsWith(".class")) {
String className = packageName + "." + fileName.substring(0, fileName.lastIndexOf('.'));
addClass(className);
}
} else if (file.isDirectory()) {
if (file.listFiles() == null) {
return;
}
for (File listFile : file.listFiles()) {
scanFile(listFile, packageName);
}
}
}
/*** 嵌套扫描* @param file 文件* @param basePackage 基础包名*/
private void scanFile(File file, String basePackage) {
if (file == null) {
return;
}
if (file.isFile()) {
final String fileName = file.getName();
if (fileName.endsWith(".class")) {
String className = basePackage + "." + fileName.substring(0, fileName.lastIndexOf('.'));
addClass(className);
}
} else if (file.isDirectory()) {
if (file.listFiles() == null) {
return;
}
basePackage = basePackage + "." + file.getName();
for (File listFile : file.listFiles()) {
scanFile(listFile, basePackage);
}
}
}
public void addClass(String className) {
Class<?> aClass = null;
try {
aClass = classLoader.loadClass(className);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
classes.add(aClass);
}
}
二、EnumerationIter 迭代器
public class EnumerationIter<E> implements Iterator<E>, Iterable<E>, Serializable {
private static final long serialVersionUID = 1L;
private final Enumeration<E> e;
public EnumerationIter(Enumeration<E> enumeration) {
this.e = enumeration;
}
@Override
public boolean hasNext() {
return e.hasMoreElements();
}
@Override
public E next() {
return e.nextElement();
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public Iterator<E> iterator() {
return this;
}
}
三、 批量注册Bean需要集成Spring提供的ImportBeanBeanDefinitionRegistrar接口。
public class BeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(ListenerScan.class.getName()));
if (annoAttrs != null) {
String[] stringArray = annoAttrs.getStringArray("value");
for (String packageName : stringArray) {
ClassScanner classScanner = new ClassScanner(packageName, Thread.currentThread().getContextClassLoader());
Set<Class<?>> scan = classScanner.scan();
for (Class<?> aClass : scan) {
if (aClass.isInterface() || aClass.isAnonymousClass() || aClass.isEnum()) {
continue;
}
registry.registerBeanDefinition(aClass.getName(), new RootBeanDefinition(aClass));
}
}
}
}
}
四、创建注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Import({BeanDefinitionRegister.class})
public @interface ListenerScan {
@AliasFor("basePackages") String[] value() default {};
@AliasFor("value") String[] basePackages() default {};
}
五、将BeanDefinitionRegister 类引入配置文件中
@Import({BeanDefinitionRegister.class})
@Configuration
public class SecurityBeanConfig {
}
六、将注解配置到启动类上
@EnableAsync
@MapperScan(basePackages = "com.aaa.bbb.*.mapper")
@SpringBootApplication
@ComponentScan(basePackages = {
"com.aaa.bbb.web",
}, excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {
AuditRecordAspect.class,
OperateIdentityAccountInjectInterceptor.class
}))
@ListenerScan("com.jianxinyun.health.web.service.strategy")
public class HealthApplication {
public static void main(String[] args) {
SpringApplication.run(HealthApplication.class, args);
}
}