美文网首页
java反射两种实现方式

java反射两种实现方式

作者: 探索者_逗你玩儿 | 来源:发表于2019-02-22 22:14 被阅读0次

    反射是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。Java中有两种方式实现反射,接下来我们来一一分析一下。
    1.通过java体系自带的反射机制,首先我们来看一个例子。

    • 定义一个接口
    public interface GoodService {
    
        String sayHello(String name);
    
    }
    
    • 添加实现类
    
    public class GoodServiceImpl implements GoodService {
        @Override
        public String sayHello(String name) {
            return name + " 你好";
        }
    }
    
    • 定义动态反射的代理类
    public class ControllerProxy implements InvocationHandler {
    
        private GoodService goodService;
    
        public ControllerProxy(GoodService goodService) {
            this.goodService = goodService;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("before");
            Object value = method.invoke(goodService,args);
            System.out.println("after");
            return value;
        }
    }
    
    
    • 最后测试一下
    public class GoodClient {
    
    
        /**
         *
         * @param args
         */
        public static void main(String[] args){
    
            GoodService goodService = new GoodServiceImpl();
    
            ControllerProxy proxy = new ControllerProxy(goodService);
            GoodService gs = (GoodService) Proxy.newProxyInstance(proxy.getClass().getClassLoader(),goodService.getClass().getInterfaces(),proxy);
            String dd = gs.sayHello("张三");
            System.out.println(dd);
    
     }
    
    }
    
    

    通过上面的列子可以发现,如果我们需要对接口进行扩展则无须对源码进行修改,只需对代理类进行扩展即可达到目的,所以反射机制提供了一种对Java扩展的方式,这种方式无侵入性。但是这种方式也不是十全十美,也有自己的瓶颈,首先被代理的只能是接口,这样就限制了使用范围,其次是性能问题,通过反射获取对象的属性的值要远比直接通过属性取值,最后反射的应用会模糊应用内实际要发生的事。
    2.除了java自带的反射机制外,另一种实现方式就是cglib,cglib完全避开了java自带的反射机制带来的问题,cglib不仅仅可以代理接口,同时可以给普通类进行代理,同时它采用fastclass机制为代理类和被代理类各生成一个Class,这个Class会为代理类或被代理类的方法分配一个index(int类型)。
    这个index当做一个入参,FastClass就可以直接定位要调用的方法直接进行调用,这样省去了反射调用,所以调用效率比JDK动态代理通过反射调用高。接下来我们撸段代码来看看

    • 直接定义cglib代理类
    public class MethodInterProxy implements MethodInterceptor {
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("before");
            Object obj = methodProxy.invokeSuper(o, objects);
            System.out.println("after");
            return  obj;
        }
    }
    
    • 实现类直接采用上面的实现类
    • 运行结果
    public class GoodClient {
    
    
        /**
         *
         * @param args
         */
        public static void main(String[] args){
    
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(GoodServiceImpl.class);
            MethodInterProxy mproxy = new MethodInterProxy();
            enhancer.setCallbacks(new Callback[]{NoOp.INSTANCE,mproxy});
            enhancer.setCallbackFilter(new MethodFilter());
            GoodService gsd = (GoodService) enhancer.create();
            String ds = gsd.sayHello("DE");
            System.out.println(ds);
    
        }
    
    }
    
    

    通过上面的例子可以看到cglib直接对实现类进行代理,cglib底层采用ASM进行字节码生成,这种方式远比jdk自带的反射机制要复杂。
    最后两者进行对比
    1.JDK动态代理是实现了被代理对象的接口,Cglib是继承了被代理对象。
    2.JDK和Cglib都是在运行期生成字节码,JDK是直接写Class字节码,Cglib使用ASM框架写Class字节码,Cglib代理实现更复杂,生成代理类比JDK效率低。
    3.JDK调用代理方法,是通过反射机制调用,Cglib是通过FastClass机制直接调用方法,Cglib执行效率更高。

    相关文章

      网友评论

          本文标题:java反射两种实现方式

          本文链接:https://www.haomeiwen.com/subject/ojklyqtx.html