应该是在YuQ中使用SpringBoot吧,或者是在SpringBoot中使用YuQYuQ直接引入Spring-Data-Jpa会有个异常,虽然不影响运行,但是看着贼不爽,所以试试看看能不能把SpringBoot整合进去

已知问题:SpringAop不工作

1、把账号以及密码配置在application.yml

格式如下:

yuq:
  art:
    qq:
    password:
    master: 734669014

与其配置对应的配置类

@ConfigurationProperties(prefix = "yuq.art")
@Component
class ArtConfig {
    var qq: Long = 0
    var password: String = ""
    var master: Long = 0
}

@ConfigurationProperties(prefix = "yuq.art")
@Component
public class ArtConfig {
    private Long qq;
    private String password;
    private Long master;
}

2、启动类

由于YuQ会在运行时对class进行字节码增强,其依赖于YuQClassLoader,所以使用YuQClassLoader来启动SpringBoot

@SpringBootApplication
class KuKuBotApplication

fun main(args: Array<String>) {
    AppClassloader.registerBackList(listOf("ch.qos",
        "org.springframework", "org.hibernate", "org.aopalliance", "com.querydsl"))
    val appClassLoader = AppClassloader(KuKuBotApplication::class.java.classLoader)
    Thread.currentThread().contextClassLoader = appClassLoader
    val clazz = appClassLoader.loadClass("org.springframework.boot.SpringApplication")
    val method = clazz.getMethod("run", Class::class.java, Array<String>::class.java)
    method.invoke(null, KuKuBotApplication::class.java, args)
}

@SpringBootApplication
public class KuKuBotApplication {
    public static void main(String[] args) {
        try {
            AppClassloader.registerBackList(List.of("ch.qos",
                    "org.springframework", "org.hibernate", "org.aopalliance", "com.querydsl"));
            AppClassloader appClassLoader = new AppClassloader(KuKuBotApplication.class.getClassLoader());
            Thread.currentThread().setContextClassLoader(appClassLoader);
            SpringApplication.run(KuKuBotApplication.class);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

3、配置YuQ以及Spring

扫包路径以及Spring的module

# 扫包路径
yu.scanPackages=me.kuku.yuq
# SpringMoudle类得全类名
yu.modules=me.kuku.yuq.config.SpringModule
yu.context.mode=single

开启spring`bean`懒加载

spring:
  main:
    lazy-initialization: true

4、初始化YuQ

@Component
class ArtInit(
    @Suppress("unused") private val springUtils: SpringUtils,
    private val artConfig: ArtConfig
): ApplicationRunner {

    private var app: DefaultApp? = null

    private val log = LoggerFactory.getLogger(ArtInit::class.java)

    override fun run(args: ApplicationArguments?) {
        System.getProperties()["yuq.art.noUI"] = "${artConfig.qq}|${artConfig.password}|0"
        val startTime = System.currentTimeMillis()
        app = DefaultApp()
        app?.start()
        val overTime = System.currentTimeMillis()
        log.info("Done! ${(overTime - startTime).toDouble() / 1000}s.")

        println(" __  __     ____ \n" +
                " \\ \\/ /_ __/ __ \\\n" +
                "  \\  / // / /_/ /\n" +
                "  /_/\\_,_/\\___\\_\\\n")
        println("感谢您使用 YuQ 进行开发,在您使用中如果遇到任何问题,可以到 Github,Gitee 提出 issue,您也可以添加 YuQ 的开发交流群(696129128)进行交流。")
    }

    @PreDestroy
    fun close() {
        app?.stop()
    }

}

class SpringModule: com.IceCreamQAQ.Yu.module.Module {

    @Inject
    private lateinit var yuContext: YuContext

    override fun onLoad() {
        val applicationContext = SpringUtils.applicationContext
        val annotationConfigApplicationContext = applicationContext as AnnotationConfigApplicationContext
        annotationConfigApplicationContext.registerBean("context", YuContext::class.java, Supplier { yuContext })
        val names = applicationContext.beanDefinitionNames
        val clazzList = mutableListOf<Class<*>>()
        for (name in names) {
            val clazzTemp = applicationContext.getType(name)
            val ss = clazzTemp?.superclass
            val list = listOf(clazzTemp, ss)
            for (clazz in list) {
//                if (clazz?.isAnnotationPresent(GroupController::class.java) == true || clazz?.isAnnotationPresent(PrivateController::class.java) == true ||
//                    clazz?.isAnnotationPresent(EventListener::class.java) == true || clazz?.isAnnotationPresent(JobCenter::class.java) == true) {
//                    clazzList.add(clazz)
//                }
                if (clazz?.isAnnotationPresent(Component::class.java) == true || clazz?.isAnnotationPresent(Controller::class.java) == true ||
                    clazz?.isAnnotationPresent(Service::class.java) == true) {
                    clazzList.add(clazz)
                }
            }
        }
        val classContextMap = yuContext::class.java.declaredFields.first { it.name == "classContextMap" }
            .also { it.isAccessible = true }.get(yuContext) as MutableMap<String, ClassContext>
        for (clazz in clazzList) {
            val bean = applicationContext.getBean(clazz)
            val name = clazz.name
            val beanClazz = bean::class.java
            yuContext.injectBean(bean)
            val classContext =
                ClassContext(name, beanClazz, false, null, bean, mutableMapOf("" to bean), null, null)
            classContextMap[name] = classContext
        }
    }
}

@Component
public class ArtInit implements ApplicationRunner {

    @Autowired
    private SpringUtils springUtils;
    @Autowired
    private ArtConfig artConfig;

    private DefaultApp app = null;

    private final Logger log = (Logger) LoggerFactory.getLogger(ArtInit.class);

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.getProperties().setProperty("yuq.art.noUI", artConfig.getQq() + "|" + artConfig.getPassword() + "|0");
        long startTime = System.currentTimeMillis();
        app = new DefaultApp();
        app.start();
        long overTime = System.currentTimeMillis();
        log.info("Done! " + Long.valueOf((overTime - startTime)).doubleValue() / 1000 + "s.");
        System.out.println(" __  __     ____ \n" +
                " \\ \\/ /_ __/ __ \\\n" +
                "  \\  / // / /_/ /\n" +
                "  /_/\\_,_/\\___\\_\\\n");
        System.out.println("感谢您使用 YuQ 进行开发,在您使用中如果遇到任何问题,可以到 Github,Gitee 提出 issue,您也可以添加 YuQ 的开发交流群(696129128)进行交流。");
    }

    @PreDestroy
    public void close() {
        app.stop();
    }
}

public class SpringModule implements Module {

    @Inject
    private YuContext yuContext;

    @Override
    public void onLoad() {
        ApplicationContext applicationContext = SpringUtils.applicationContext;
        AnnotationConfigApplicationContext annotationConfigApplicationContext = (AnnotationConfigApplicationContext) applicationContext;
        annotationConfigApplicationContext.registerBean("context", YuContext.class, () -> yuContext);
        String[] names = applicationContext.getBeanDefinitionNames();
        List<Class<?>> clazzList = new ArrayList<>();
        for (String name : names) {
            Class<?> clazzTemp = applicationContext.getType(name);
            if (clazzTemp != null) {
                Class<?> ss = clazzTemp.getSuperclass();
                List<Class<?>> list = List.of(clazzTemp, ss);
                for (Class<?> clazz : list) {
                    if (clazz.isAnnotationPresent(Component.class) || clazz.isAnnotationPresent(Controller.class)
                            || clazz.isAnnotationPresent(Service.class)) {
                        clazzList.add(clazz);
                    }
                }
            }
        }
        Field[] fields = yuContext.getClass().getDeclaredFields();
        Optional<Field> optional = Arrays.stream(fields).filter(it -> it.getName().equals("classContextMap")).findFirst();
        if (optional.isPresent()) {
            try {
                Field field = optional.get();
                field.setAccessible(true);
                Map<String, ClassContext> classContextMap = (Map<String, ClassContext>) field.get(yuContext);
                for (Class<?> clazz : clazzList) {
                    Object bean = applicationContext.getBean(clazz);
                    String name = clazz.getName();
                    Class<?> beanClazz = bean.getClass();
                    yuContext.injectBean(bean);
                    ClassContext classContext = new ClassContext(name, beanClazz, false, null, bean, Map.of("", bean), null, null);
                    classContextMap.put(name, classContext);
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

工具类SpringUtils

@Component
class SpringUtils: ApplicationContextAware {

    companion object {

        lateinit var applicationContext: ApplicationContext

        inline fun <reified T: Any> getBean(name: String): T {
            return applicationContext.getBean(name) as T
        }

        inline fun <reified T: Any> getBean() = applicationContext.getBean(T::class.java)

    }

    override fun setApplicationContext(applicationContext: ApplicationContext) {
        Companion.applicationContext = applicationContext
    }
}

@Component
public class SpringUtils implements ApplicationContextAware {
    
    public static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
        SpringUtils.applicationContext = applicationContext;
    }
}

最后修改:2022 年 06 月 20 日
如果觉得我的文章对你有用,请随意赞赏