当前位置:   article > 正文

利用aop实现热拔插(类似于插件)_aoppluginfactory

aoppluginfactory

现在有这么一个需求:就是我们日志的开与关是交给使用人员来控制的,而不是由我们开发人员固定写死的。大家都知道可以用aop来实现日志管理,但是如何动态的来实现日志管理呢?aop源码中的实现逻辑中有这么一个步骤,就是会依次扫描Advice的实现类,然后执行。我们要做的就是自定义一个advice的实现类然后,在用户想要开启日志的时候就把advice加到项目中来,关闭日志的时候就把advice剔除就行了。好了知道思路了那么开始敲代码吧;

1:编写我们的插件

新建一个maven项目名字为pluginLog,项目中编写一个类名字为pluginLog

public class pluginLog implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("Log");
    }

    public static void main(String[] args) {
        System.out.println("日志");
    }
    public pluginLog() {
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2:打jar包

利用maven命令把插件打成jar包,这个jar包就是我们的插件。打包过程:win+r输入cmd回车,进入dos窗口切换到我们的插件项目如下,输入mvn clean package回车,jar包就打包好了。或者直接使用 IDEA 打包
在这里插入图片描述
在这里插入图片描述

3:找到jar包

删除plugin-0.0.1-SNAPSHOT.jar把plugin-0.0.1-SNAPSHOT.jar.original的这个jar包改个名字为plugin-0.0.1-SNAPSHOT.jar
在这里插入图片描述复制jar到我们的测试目录,我这里是在d盘下的com下的zzh中
在这里插入图片描述

4:实现插件热拔插核心代码

另外新建一个项目,名字为pluginUse
在这里插入图片描述

编写我们的插件配置信息pluginConfig.json放在resource目录下内容如下

{ “name”:“aop插件”,
“configs”:[{
“id”:“1”,
“name”:“测试插件”,
“active”:false,
//加载类
“className”:“com.zzh.pluginLog”,
//“className”:“com.destiny.plugin.TestPlugin”,
// jar包路径
“jarRemoteUrl”:“jar:file:/D:/com/zzh/pluginLog.jar!/” }] }

接着开始编写我们的激活插件的代码,主要是通过applicationContext来得到所有的bean,然后做判断,哪些bean要被加上我们jar包中的通知。这里我们需要搞清楚这几个概念
Advised: 包含所有的Advisor 和 Advice

Advice: 通知拦截器

Advisor: 通知 + 切入点的适配器

/**
     * @param
     * @method 激活插件
     */
    public void activePlugin(String id) {
        if (!cachePluginConfigs.containsKey(id)) {
            throw new RuntimeException(String.format("这个插件不存在id=%s", id));
        }
        //获取插件的配置信息
        PluginConfig pluginConfig = cachePluginConfigs.get(id);
        //设置激活状态
        pluginConfig.setActive(true);
        //拿到所有的beanDefinition
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        //为符合条件的bean加上插件
        for (String beanDefinition : beanDefinitionNames) {
            Object bean = applicationContext.getBean(beanDefinition);
            //bean是本类跳过
            if (bean == this) {
                continue;
            }
            //bean是null跳过
            if (bean == null) {
                continue;
            }
            //bean
            if (!(bean instanceof Advised)) { // 判断是否属于通知对象
                continue;
            }
            //判断当前bean是否已经有通知拦截器作用,如果有说明已经激活过了直接跳过
            if (find(bean, pluginConfig.getClassName())) {
                continue;
            }
            try {
                //根据插件的配置信息生成通知
                Advice advice = bulidAdvice(pluginConfig);
                //给bean加上通知
                ((Advised) bean).addAdvice(advice);
            } catch (Exception e) {
                System.out.println("插件添加失败");
            }

        }

    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

bulidAdvice

通过类加载器,通过jar中的pluginLog.class实例化对象,然后返回此advice

/**
     * @param
     * @method 创建通知
     */
    public Advice bulidAdvice(PluginConfig pluginConfig) {
        Advice plugin = null;
        try {
            Boolean isLoad = false;
            //获取jar包url路径
            URL targetUrl = new URL(pluginConfig.getJarRemoteUrl());
            //获取系统类加载器
            URLClassLoader jarclassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
            //遍历所有jar包url比较是否已经加载过插件
            URL[] urLs = jarclassLoader.getURLs();
            for (URL url : urLs) {
                if (targetUrl.equals(url)) {
                    out.println("jar包已经加载过了");
                    isLoad = true;
                    break;
                }
            }
            //没有加载过插件时
            if (!isLoad) {
                //加载jar包
                Method addurl = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
                addurl.setAccessible(true);
                addurl.invoke(jarclassLoader, targetUrl);
            }
            if (cachePlugins.containsKey(pluginConfig.getName())) {
                return cachePlugins.get(pluginConfig.getName());
            }
            //加载jar包中路径为pluginConfig.getClassName()的类,生成class文件
            Class<?> pluginClass = jarclassLoader.loadClass(pluginConfig.getClassName());
            //通过class生成实例对象
            plugin = (Advice) pluginClass.newInstance();
            cachePlugins.put(pluginConfig.getName(), plugin);

        } catch (MalformedURLException | ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
        return plugin;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

到此激活插件代码就完成了,做测试只需编写controller调用此方法就行了
取消插件代码类似,完整代码链接 https://gitcode.net/qq_42875345/rebacha-master

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/86665
推荐阅读
相关标签
  

闽ICP备14008679号