zoukankan      html  css  js  c++  java
  • AOP

    AOP

    ExtensionLoader#loadDirectory

    加载META-INF/services/,META-INF/dubbo/和META-INF/dubbo/internal/ 下与当前类型全类名相同的文件

    private void loadDirectory(Map<String, Class<?>> extensionClasses, String dir) {
            String fileName = dir + type.getName();
            try {
                Enumeration<java.net.URL> urls;
                ClassLoader classLoader = findClassLoader();
                 // 加载当前类全限定名的文件
                if (classLoader != null) {
                    urls = classLoader.getResources(fileName);
                } else {
                    urls = ClassLoader.getSystemResources(fileName);
                }
                if (urls != null) {
                    while (urls.hasMoreElements()) {
                        java.net.URL resourceURL = urls.nextElement();
                        loadResource(extensionClasses, classLoader, resourceURL);
                    }
                }
            } catch (Throwable t) {
                ...
            }
        }
    

    ExtensionLoader#loadClass

    private void loadClass(Map<String, Class<?>> extensionClasses, java.net.URL resourceURL, Class<?> clazz, String name) throws NoSuchMethodException {
        if (!type.isAssignableFrom(clazz)) {
            throw ...
        }
      	//当前接口对应的文件下的被@Adaptive标识的类
        if (clazz.isAnnotationPresent(Adaptive.class)) {
            if (cachedAdaptiveClass == null) {
                cachedAdaptiveClass = clazz;
            } else if (!cachedAdaptiveClass.equals(clazz)) {
                throw ...
            }
        } else if (isWrapperClass(clazz)) {
          //如果当前扫描的类有个构造方法,并且该构造方法的参数与当前类型相同(type),保存到cachedWrapperClasses,这里是实现AOP的一个关键点
            Set<Class<?>> wrappers = cachedWrapperClasses;
            if (wrappers == null) {
                cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
                wrappers = cachedWrapperClasses;
            }
            wrappers.add(clazz);
        } else {
            clazz.getConstructor();
             //校验扩展名, 这里可以发现扩展名可以为空 即配置文件不使用key=value,学JDK直接使用value
          	// 那么1.该扩展类上有@Extension注解 或者2.该类的名字的末尾包含当前类的名字 
            // 即: 如果当前类叫 Qiao  那么该类的名字为 AbcQiao 那么这个类的扩展名就是abc 详见:注1
            if (name == null || name.length() == 0) {
                name = findAnnotationName(clazz);
                if (name.length() == 0) {
                    throw ...
                }
            }
            String[] names = NAME_SEPARATOR.split(name);
            if (names != null && names.length > 0) {
                Activate activate = clazz.getAnnotation(Activate.class);
                if (activate != null) {
                    cachedActivates.put(names[0], activate);
                }
                for (String n : names) {
                    if (!cachedNames.containsKey(clazz)) {
                        cachedNames.put(clazz, n);
                    }
                    Class<?> c = extensionClasses.get(n);
                    if (c == null) {
                      	//加载不被@Adaptive标识、不是aop的其他扩展类
                        extensionClasses.put(n, clazz);
                    } else if (c != clazz) {
                        throw ...
                    }
                }
            }
        }
    }
    

    注1: 配置文件中不使用key=value的形式,使用JDK的 value形式

    ExtensionLoader.getExtensionLoader(Qiao.class).getExtension("abc")
    

    配置文件 META-INF/services/per.qiao.AbcQiao 如下

    per.qiao.AbcQiao
    

    注意,这个类的simpleName以Qiao结尾.

    注意到上面,已经将当前类型(@SPI标识)的aop类型放到了cachedWrapperClasses、wrappers中.

    在当我们调用getExtension方法时会调用createExtension方法,

    createExtension方法如下

    private T createExtension(String name) {
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) {
            throw findException(name);
        }
        try {
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
          	// 对获取的扩展类进行IOC处理
            injectExtension(instance);
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
    			//这里将aop扩展类进行链式处理,实例化并进行IOC处理
                for (Class<?> wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            return instance;
        } catch (Throwable t) {
            ...
        }
    }
    

    上面方法会返回一个链式条用的第一个入口对象, 比如有两个AOP扩展类, A和B,目标扩展类是Target,

    那么调用方法就是 A.method->B.method->Target.method (A,和B的执行顺序取决于你的文件中的配置顺序)。

    还有要注意的是AOP类型要和当前类型,放在同一个文件里面(也可以说是目标Target)

    了解到那么多之后,我们来自定义一个AOP实现。

    AOP的Demo

    1. 自定义一个协议
    // 设置默认扩展类型
    @SPI(value = MyExtProtocol.NAME)
    public interface MyProtocol {
    
        String getName();
    
        Integer getSize(String name);
    }
    
    1. 默认扩展类(目标执行的扩展类)
    public class MyExtProtocol implements MyProtocol {
      
        public static final String NAME = "myExt";
      
        @Override
        public String getName() {
            System.out.println("MyExtProtocol.getName" + "目标方法被调用");
            return "MyExtProtocol.getName";
        }
    
        @Override
        public Integer getSize(String name) {
            return null;
        }
    }
    
    1. AOP类型
    /**
     * MyProtocol类型的AOP扩展类
     * 与目标扩展类实现同一个接口
     */
    public class MyProtocolWrapper implements MyProtocol {
    
      	/**
      	 * AOP链式调用中的一节,这里我们只有一个AOP扩展类,故这个就是目标扩展类
      	 */
        private MyProtocol myProtocol;
    
        public MyProtocolWrapper(MyProtocol myProtocol) {
            this.myProtocol = myProtocol;
        }
    
        @Override
        public String getName() {
            System.out.println("MyProtocolWrapper.getName === " + "前置方法被调用");
            String name = myProtocol.getName();
            System.out.println("MyProtocolWrapper.getName === " + "后置方法被调用");
          
            return name;
        }
    
        @Override
        public Integer getSize(String name) {
            System.out.println("MyProtocolWrapper.getSize === " + "前置方法被调用");
            Integer size = myProtocol.getSize(name);
            System.out.println("MyProtocolWrapper.getSize === " + "后置方法被调用");
            return size;
        }
    }
    
    1. 扩展类配置文件
    #  目标扩展类
    myExt=per.qiao.myprotocol.impl.MyExtProtocol
    # AOP类型
    myWrapper=per.qiao.myprotocol.wrapper.MyProtocolWrapper
    
    1. 调用
    MyProtocol myExt = ExtensionLoader.getExtensionLoader(MyProtocol.class).getExtension("myExt");
    myExt.getName();
    

    一个简单的AOP就完成了.

  • 相关阅读:
    移动端web app开发备忘
    HDU 5391-Zball in Tina Town(数论)
    LeetCode:Invert Binary Tree
    Mongo集群之主从复制
    Cocos2d-x--iOS平台lua加密成luac资源方法和Jsc文件&lt;MAC平台开发试用--windows平台暂未研究&gt;
    优秀程序猿因何而优秀?
    Java Exception和Error的差别
    【Android开发】之Fragment与Acitvity通信
    Draw the RGB data from kinect C++ via opengl
    使用Opencv2遇到error C2061: 语法错误: 标识符dest
  • 原文地址:https://www.cnblogs.com/qiaozhuangshi/p/11007077.html
Copyright © 2011-2022 走看看