zoukankan      html  css  js  c++  java
  • 使用Java原生代理实现数据注入

    本文由博主原创,转载请注明出处
    完整源码下载地址 https://github.com/MatrixSeven/JavaAOP
    上一篇,咱们说了使用Java原生代理实现AOP的简单例子,然么就不得不说一下Annotation这个东西了.注解(Annotation)是什么.吓得小柒君赶紧百度下:

    1. 注解基础知识点
    2. 定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
      作用分类:
    3. 编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
    4. 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
    5. 编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】

    and so on….如果你对注解(Annotation)还没有了解请左移百度百科:Annotation和Java 注解
    啊,,是不是很眼熟,这个不就是经常看到的那个@Override神马的么…原来这个东西就叫做注解啊.
    —–引至百度:我个人使用的理解,annotation是一种在类、类型、属性、参数、局部变量、方法、构造方法、包、annotation本身等上面的一个附属品(ElementType这个枚举中有阐述),他依赖于这些元素而存在,他本身并没有任何作用,annotation的作用是根据其附属在这些对象上,根据外部程序解析引起了他的作用,例如编译时的,其实编译阶段就在运行:java Compiler,他就会检查这些元素,例如:@SuppressWarnings、@Override、@Deprecated等等;


    的确是,但是想想Spring的IOC依赖注入,控制反转@xxx(xxx=xxx)然后Bean里就被赋值了,是不是觉得好帅,哈,是不是也觉得好神奇?
    是不是我创建一个注解,然后把他作用到类上就能赋值了?赶紧试一试…

    首先,创建一个注解,用关键字@interface来声明,这是一个注解类.@Target来声明注解目标,
    @Retention用来说明该注解类的生命周期.

    package proxy.annon;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD,ElementType.METHOD})
    public @interface Seven {
        public String value() default "小黑";
        public String Property() default "无属性";
    }
    

    然后还用咱们昨天的写的JavaBean,加上注解后的样子就是:

    package proxy;
    import proxy.annon.Seven;
    import proxy.imp.AnimalInterface;
    public class DogImp implements AnimalInterface {
        @Seven(value = "Lumia")
        private String name;
        private String Property;
        public DogImp() {
        }
        @Override
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public String getName() {
            return this.name;
        }
        @Override
        public void say() {
            System.out.println("小狗:汪汪汪汪.....");
        }
        @Override
        @Seven(Property = "水陆两栖战士")
        public void setProperty(String Property) {
            this.Property = Property;
        }
        @Override
        public void getProperty() {
            System.out.println(this.name + this.Property);
        }
    }
    

    迫不及待运行下:

    package proxy;
     
    public class Test {
     
        public static void main(String[] args) {
            DogImp dogImp = new DogImp();
            System.out.println(dogImp.getName());
            dogImp.getProperty();
        }
    }
     
    输出:
    null
    nullnull
    

    额.好伤心,表示并没有什么效果,那@的注入到底是怎么实现的呢….

    转了一圈,还得依赖咱们的反射大军哈哈…..

    赶紧改造下昨天的Demo,让其能够注解..咱们一起来…

    注解已经创建好了,怎么让咱们的注解产生效果呢,赶紧动手写个AnnoInjection类.

    用来实现注解的内容的注入..

    但是要注意,让注如属性的时候,一定要有对用的get/set方法,如果访问级别为private则可以直接使用
    属性的set(obj, value),如果为public,则需要自己获取方法,然后调用方法的invoke

    package proxy.annon;
     
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
     
    public class AnnoInjection {
     
        public static Object getBean(Object obj) {
            try {
                // 获得类属性
                Field f[] = obj.getClass().getDeclaredFields();
                // 遍历属性
                for (Field ff : f) {
                    // 获得属性上的注解
                    Seven s = ff.getAnnotation(Seven.class);
                    if (s != null) {
                        System.err.println("注入" + ff.getName() + "属性" + "tt" + s.value());
                        // 反射调用public set方法,如果为访问级别private,那么可以直接使用属性的set(obj,
                        // value);
                        obj.getClass()
                                .getMethod("set" + ff.getName().substring(0, 1).toUpperCase() + ff.getName().substring(1),
                                        new Class[] { String.class })
                                .invoke(obj, s.value());
                    }
                }
                // 获得所有方法
                Method m[] = obj.getClass().getDeclaredMethods();
                for (Method mm : m) {
                    // 获得方法注解
                    Seven s = mm.getAnnotation(Seven.class);
                    if (s != null) {
                        System.err.println("注入" + mm.getName() + "方法" + "t" + s.Property());
                        mm.invoke(obj, s.Property());
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return obj;
        }
     
    }
    

    这样呢,就实现了属性的方法的注入..在哪里调用呢…….

    哦,,查看之前的AnimalFactory代码,会发现在getAnimalBase里有

    Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                    obj.getClass().getInterfaces(),
                    new AOPHandle(obj,method))
    

    很明显,咱们的动态代理new AOPHandle(obj,method)时传入了反射生成obj.然后实现代理拦截直接,
    咱们来先处理这个obj.所以咱们简单修改下这个就好了
    修改后的样子:

    /***
         * 获取对象方法
         * @param obj
         * @return
         */
        private static Object getAnimalBase(Object obj,AOPMethod method){
            //获取代理对象
            return Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                    obj.getClass().getInterfaces(),
                    new AOPHandle(AnnoInjection.getBean(obj),method));
        }
    

    soga….看起来完美了,,赶紧跑起来试一试..

    不对..之前的方法拦截太罗嗦,咱们只拦截getProperty方法..好吧

    要不然输出太恶心了….

    修改后的AOPTest….

    package proxy;
     
    import java.lang.reflect.Method;
     
    import org.junit.runner.RunWith;
    import org.junit.runners.BlockJUnit4ClassRunner;
    import proxy.imp.AOPMethod;
    import proxy.imp.AnimalInterface;
     
    @RunWith(BlockJUnit4ClassRunner.class)
    public class AOPTest {
     
        public static void main(String[] args) {
     
            AnimalInterface dog = AnimalFactory.getAnimal(DogImp.class, new AOPMethod() {
                // 这里写方法执行前的AOP切入方法
                public void before(Object proxy, Method method, Object[] args) {
                    if (method.getName().equals("getProperty")) {
                        System.err.println("成功拦截" + method.getName() + "方法,启动");
                    }
                }
     
                // 这里系方法执行后的AOP切入方法
                public void after(Object proxy, Method method, Object[] args) {
                    if (method.getName().equals("getProperty"))
                        System.err.println("成功拦截" + method.getName() + "方法,结束");
     
                }
            });
            dog.say();
            String name1 = "我的名字是" + dog.getName();
            System.out.println(name1);
            dog.setName("二狗子");
            String name2 = "我的名字是" + dog.getName();
            System.out.println(name2);
            dog.getProperty();
        }
    }
    

    然后给我run起来….

    beauty,成功出来了呢..赶紧上个图,高兴下..

    截图

    哈哈哈……大家是够有许多感悟呢,咱们下次再见

    吾爱Java(QQ群):170936712

  • 相关阅读:
    [杂题]FZU2190 非提的救赎
    [模拟]ZOJ3480 Duck Typing
    [模拟]ZOJ3485 Identification Number
    [数论]ZOJ3593 One Person Game
    [博弈]ZOJ3591 Nim
    [杂题]URAL1822. Hugo II's War
    二分图相关
    KMP算法详解
    中国国家集训队论文集目录(1999-2009)
    最短路Dijkstra算法的一些扩展问题
  • 原文地址:https://www.cnblogs.com/seven007/p/6261807.html
Copyright © 2011-2022 走看看