发布日期:2024-07-03 15:20 点击次数:73
现在数据搞定处事中有广阔搞定任务,当其中任一搞定任务有改革需要升级或新增一个搞定任务时,都需要将数据搞定处事重启,会影响其他搞定任务的平方初始。
2、缱绻或者动态启动、住手任一搞定任务或者动态升级、添加搞定任务启动、住手搞定任务或升级、添加搞定任务不成影响其他任务3、决议为了相沿业务代码尽量的解耦,把部分业务功能通过动态加载的步地加载到主重要中,以高傲可插拔式的加载、组合式的部署。联结xxl-job任务攻击框架,将数据搞定任务作念成xxl-job任务的步地注册到xxl-job中,浅近颐养经管。二、动态加载1、自界说类加载器URLClassLoader 是一种稀奇的类加载器,不错从指定的 URL 中加载类和资源。它的主要作用是动态加载外部的 JAR 包或者类文献,从而杀青动态彭胀哄骗重要的功。为了便于经管动态加载的jar包,自界说类加载器领受URLClassloader。
平乐县达大棉类有限公司 53); font-size: 16px; letter-spacing: 0.8px; text-align: left; word-spacing: 0.8px; background-color: rgb(255,平乐县达大棉类有限公司 255, 255); border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;">/** * 自界说类加载器 * * @author lijianyu * @date 2023/04/03 17:54 **/public class MyClassLoader extends URLClassLoader { private Map<String, Class<?>> loadedClasses = new ConcurrentHashMap<>(); public Map<String, Class<?>> getLoadedClasses() { return loadedClasses; } public MyClassLoader(URL[] urls, ClassLoader parent) { super(urls, parent); } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { // 从已加载的类皆麇集得到指命称号的类 Class<?> clazz = loadedClasses.get(name); if (clazz != null) { return clazz; } try { // 调用父类的findClass方法加载指命称号的类 clazz = super.findClass(name); // 将加载的类添加到已加载的类皆麇集 loadedClasses.put(name, clazz); return clazz; } catch (ClassNotFoundException e) { e.printStackTrace(); return null; } } public void unload() { try { for (Map.Entry<String, Class<?>> entry : loadedClasses.entrySet()) { // 从已加载的类皆麇集移除该类 String className = entry.getKey(); loadedClasses.remove(className); try{ // 调用该类的destory方法,回收资源 Class<?> clazz = entry.getValue(); Method destory = clazz.getDeclaredMethod("destory"); destory.invoke(clazz); } catch (Exception e ) { // 标明该类莫得destory方法 } } // 从其父类加载器的加载器脉络结构中移除该类加载器 close(); } catch (Exception e) { e.printStackTrace(); } }}自界说类加载器中,为了浅近类的卸载,界说一个map保存已加载的类信息。key为这个类的ClassName,value为这个类的类信息。同期界说了类加载器的卸载方法,卸载方法中,将已加载的类的皆麇集移除该类。由于此类可能使用系统资源或调用线程,为了幸免资源未回收引起的内存溢出,通过反射调用这个类中的destroy方法,回收资源。终末调用close方法。2、动态加载
广电 53); font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, "PingFang SC", Cambria, Cochin, Georgia, Times, "Times New Roman", serif; font-size: 16px; text-align: left; text-indent: 0em; text-wrap: wrap; word-spacing: 0.8px; background-color: rgb(255, 255, 255); line-height: 1.75; letter-spacing: 0em;">由于此面貌使用spring框架,以及xxl-job任务的机制调用动态加载的代码,因此要完成以下内容
将动态加载的jar包读到内存中将有spring注解的类,通过注解扫描的步地,扫描并手动添加到spring容器中。将@XxlJob注解的方法,通过注解扫描的步地,手动添加到xxljob本质器中。/** * @author lijianyu * @date 2023/04/29 13:18 **/@Componentpublic class DynamicLoad { private static Logger logger = LoggerFactory.getLogger(DynamicLoad.class); @Autowired private ApplicationContext applicationContext; private Map<String, MyClassLoader> myClassLoaderCenter = new ConcurrentHashMap<>(); @Value("${dynamicLoad.path}") private String path; /** * 动态加载指定旅途下指定jar包 * @param path * @param fileName * @param isRegistXxlJob 是否需要注册xxljob本质器,面貌初度启动不需要注册本质器 * @return map<jobHander, Cron> 创建xxljob任务时需要的参数设立 */ public void loadJar(String path, String fileName, Boolean isRegistXxlJob) throws ClassNotFoundException, InstantiationException, IllegalAccessException { File file = new File(path +"/" + fileName); Map<String, String> jobPar = new HashMap<>(); // 得到beanFactory DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory(); // 得到面前面貌的本质器 try { // URLClassloader加载jar包方法必须这样写 URL url = new URL("jar:file:" + file.getAbsolutePath() + "!/"); URLConnection urlConnection = url.openConnection(); JarURLConnection jarURLConnection = (JarURLConnection)urlConnection; // 得到jar文献 JarFile jarFile = jarURLConnection.getJarFile(); Enumeration<JarEntry> entries = jarFile.entries(); // 创建自界说类加载器,并加到map中浅近经管 MyClassLoader myClassloader = new MyClassLoader(new URL[] { url }, ClassLoader.getSystemClassLoader()); myClassLoaderCenter.put(fileName, myClassloader); Set<Class> initBeanClass = new HashSet<>(jarFile.size()); // 遍历文献 while (entries.hasMoreElements()) { JarEntry jarEntry = entries.nextElement(); if (jarEntry.getName().endsWith(".class")) { // 1. 加载类到jvm中 // 得到类的全旅途名 String className = jarEntry.getName().replace('/', '.').substring(0, jarEntry.getName().length() - 6); // 1.1进行反射得到 myClassloader.loadClass(className); } } Map<String, Class<?>> loadedClasses = myClassloader.getLoadedClasses(); XxlJobSpringExecutor xxlJobExecutor = new XxlJobSpringExecutor(); for(Map.Entry<String, Class<?>> entry : loadedClasses.entrySet()){ String className = entry.getKey(); Class<?> clazz = entry.getValue(); // 2. 将有@spring注解的类交给spring经管 // 2.1 判断是否注入spring Boolean flag = SpringAnnotationUtils.hasSpringAnnotation(clazz); if(flag){ // 2.2交给spring经管 BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz); AbstractBeanDefinition beanDefinition = builder.getBeanDefinition(); // 此处beanName使用全旅途名是为了驻防beanName重叠 String packageName = className.substring(0, className.lastIndexOf(".") + 1); String beanName = className.substring(className.lastIndexOf(".") + 1); beanName = packageName + beanName.substring(0, 1).toLowerCase() + beanName.substring(1); // 2.3注册到spring的beanFactory中 beanFactory.registerBeanDefinition(beanName, beanDefinition); // 2.4允许注入和反向注入 beanFactory.autowireBean(clazz); beanFactory.initializeBean(clazz, beanName); /*if(Arrays.stream(clazz.getInterfaces()).collect(Collectors.toSet()).contains(InitializingBean.class)){ initBeanClass.add(clazz); }*/ initBeanClass.add(clazz); } // 3. 带有XxlJob注解的方法注册任务 // 3.1 过滤方法 Map<Method, XxlJob> annotatedMethods = null; try { annotatedMethods = MethodIntrospector.selectMethods(clazz, new MethodIntrospector.MetadataLookup<XxlJob>() { @Override public XxlJob inspect(Method method) { return AnnotatedElementUtils.findMergedAnnotation(method, XxlJob.class); } }); } catch (Throwable ex) { } // 3.2 生成并注册方法的JobHander for (Map.Entry<Method, XxlJob> methodXxlJobEntry : annotatedMethods.entrySet()) { Method executeMethod = methodXxlJobEntry.getKey(); // 得到jobHander和Cron XxlJobCron xxlJobCron = executeMethod.getAnnotation(XxlJobCron.class); if(xxlJobCron == null){ throw new CustomException("500", executeMethod.getName() + "(),莫得添加@XxlJobCron注解设立定时计策"); } if (!CronExpression.isValidExpression(xxlJobCron.value())) { throw new CustomException("500", executeMethod.getName() + "(),@XxlJobCron参数内容诞妄"); } XxlJob xxlJob = methodXxlJobEntry.getValue(); jobPar.put(xxlJob.value(), xxlJobCron.value()); if (isRegistXxlJob) { executeMethod.setAccessible(true); // regist Method initMethod = null; Method destroyMethod = null; xxlJobExecutor.registJobHandler(xxlJob.value(), new CustomerMethodJobHandler(clazz, executeMethod, initMethod, destroyMethod)); } } } // spring bean本色注册 initBeanClass.forEach(beanFactory::getBean); } catch (IOException e) { logger.error("读取{} 文献终点", fileName); e.printStackTrace(); throw new RuntimeException("读取jar文献终点: " + fileName); } }}
以下是判断该类是否有spring注解的器用类广电
apublic class SpringAnnotationUtils { private static Logger logger = LoggerFactory.getLogger(SpringAnnotationUtils.class); /** * 判断一个类是否有 Spring 中枢注解 * * @param clazz 要查验的类 * @return true 若是该类上添加了相应的 Spring 注解;不然复返 false */ public static boolean hasSpringAnnotation(Class<?> clazz) { if (clazz == null) { return false; } //是否是接口 if (clazz.isInterface()) { return false; } //是否是抽象类 if (Modifier.isAbstract(clazz.getModifiers())) { return false; } try { if (clazz.getAnnotation(Component.class) != null
下一篇:没有了