反射和动态代理

什么是反射?
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;
这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
如果我们拿到一个类的类型信息,就可以利用反射获取其各种成员以及方法了.通过反射调用方法例子如下:

package com.reflection;

import java.lang.reflect.Method;

public class ReflectionAPI {

    public static void main(String[] args) throws Exception {
      Class<?>cla=Class.forName("java.lang.String");
      /* 
 public Method[] getMethods()返回某个类的所有公用(public)方法包括其继
 承类的公用方法,当然也包括它所实现接口的方法。
   public Method[] getDeclaredMethods()对象表示的类或接口声明的所有方法,
   包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所
   实现接口的方法。
       */
    //返回class对象所对应的类或接口中,所声明的所有方法的数组(包括私有方法)
      Method[] method=cla.getDeclaredMethods();
    //遍历输出所有方法声明
      for(Method m:method){
          System.out.println(m);

      }
    }

}

package com.reflect.method;

public class InvokeTest {

  public int add(int id,int age){

    return age;

  }
  public  String reflect(String name){
    return "hello:"+name;     
  }
}

package com.reflect.method;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
        //不用反射情况下,
        InvokeTest it=new InvokeTest();
        System.out.println(it.add(1, 10));
        System.out.println(it.reflect("张三"));
        System.out.println("---下面是使用反射的例子-----");


        //使用反射首先获取类名
        /*三种方式得到Class对象: 
  1.调用对象的getClass方法,返回该对象的Class对象 例如:String str = "aa"; Class<?> classType1 = str.getClass(); 
  getClass()方法定义在Object类中,不是静态方法,需要通过对象来调用,
  并且它声明 为final,表明不能被子类所覆写。
  (Object方法有哪些。clone()、equals()、finalize()、getClass()、
面试官问过我这个问题。偶然想起了记录下来。)
 2.Class.forName(“类的名字”);有个受查异常
 如:Class.forName("java.lang.String");
       3.Class c=类名.class  例如:String.class;
         */
        Class<InvokeTest> cla=InvokeTest.class;
/*这里有必要提一下就是Class下的newInstance()和new有什么区别?,
首先,newInstance( )是一个方法,
 * 而new是一个关键字,其次,Class下的newInstance()的使用有局限,
 * 因为它生成对象只能调用无参的构造函数,
 * 而使用new关键字生成对象没有这个限制。好,到此为止,我们总结如下:
 * Class.forName("")返回的是类
 * Class.forName("").newInstance()返回的是object.
 */
        //这里生成新的对象,用newInstance()方法。
        Object invokeTest=cla.newInstance();
        System.out.println(invokeTest instanceof InvokeTest);
        /*通过反射调用方法,首先需要获得与该方法相对应的Method对象。
         * 
         */
        // 第一个参数是方法名,第二个参数是这个方法所需要的参数的Class对象的数组
        Method method=cla.getMethod("add", new Class[]{int.class,int.class});
        Method method2=cla.getMethod("reflect", new Class[]{String.class});     
        Object object=method.invoke(invokeTest, new Object[]{1,10});
        System.out.println(object);
        Object object2= method2.invoke(invokeTest, new Object[]{"反射"});
        System.out.println(object2);



    }
}

控制台输出结果:
10
hello张三
---下面是使用反射的例子-----
true
10
hello反射

/*********************java动态代理(JDK和cglib)*************************/
java动态代理主要涉及2个类:1.interface InvocationHandler;2.class Proxy .
按照代理的创建时期,代理类可以分为两种。
静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
动态代理:在程序运行时,运用反射机制动态创建而成。
静态代理:

package neusoft.proxy.dao;

public interface Count {
  //查看账户的方法.
    public void queryCount();
   //修改账户的方法.
    public void updateCount();
}

package neusoft.proxy.impl;

import neusoft.proxy.dao.Count;

public class CountImpl implements Count{

    @Override
    public void queryCount() {
    System.out.println("**查询账户的方法**");

    }

    @Override
    public void updateCount() {

        System.out.println("**修改账户的方法**");
    }

}

package neusoft.proxy.impl;

import neusoft.proxy.dao.Count;
//这是一个代理类(增强CountImpl实现类) 
public class CountProxy implements Count{
 private CountImpl countImpl;
  //覆盖默认构造器 
    public CountProxy(CountImpl countImpl) {
        this.countImpl = countImpl;  
}

    @Override
    public void queryCount() {
        //在这些方法里面增加一些业务逻辑,增强CountImpl实现类。
        System.out.println("**事务处理之前**");
        // // 调用委托类的方法; 
        countImpl.queryCount();
        System.out.println("**事务处理之后**");
    }

    @Override
    public void updateCount() {
        System.out.println("**事务处理之前**");
        // // 调用委托类的方法; 
        countImpl.updateCount();
        System.out.println("**事务处理之后**");

    }

}

package neusoft.proxy.test;

import neusoft.proxy.impl.CountImpl;
import neusoft.proxy.impl.CountProxy;

public class CountTest {
    public static void main(String[] args) {
        CountImpl countImpl=new CountImpl();
        CountProxy countProxy=new CountProxy(countImpl);
        countProxy.queryCount();
        countProxy.updateCount();
    }

通过这些代码可以发现,CountProxy 代理类只能为Count这一个接口服务,这样必然会产生过多的代理,对比下面的动态代理差别就一目了然了。

JDK动态代理中包含一个类和一个接口:
InvocationHandler接口:
public interface InvocationHandler {
public Object invoke(Object proxy,Method method,Object[] args) throws Throwable;
}
参数说明:
Object proxy:指被代理的对象。
Method method:要调用的方法
Object[] args:方法调用时所需要的参数

可以将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject。

Proxy类:
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,此类提供了如下的操作方法:
public static Object newProxyInstance(ClassLoader loader, Class

package neusoft.proxy.dao;

public interface MyProxy {
   public void add();
 //我们再添加一个方法;
public void delete();
}

package neusoft.proxy.impl;

import neusoft.proxy.dao.MyProxy;

public class MyProxyImpl implements MyProxy{

    @Override
    public void add() {
        System.out.println("-----add方法---------------");

    }
        @Override
    public void delete() {
        System.out.println("-----delete方法--------");

    }

}

package neusoft.proxy.impl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

//这是一个代理类(增强MyProxyImpl实现类) 
public class MyDynamicProxy implements InvocationHandler{

    private Object pro;
   public MyDynamicProxy(Object obj){      
       this.pro=obj;
   }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
                  doBefore(method);
        System.out.println(proxy.getClass().getSimpleName());       
         Object result= method.invoke(pro, args);

        return result;
    }

      public static void doBefore(Method method){

        System.out.println(method.getName()+"方法执行*****doBefore******");
      }

}

package neusoft.proxy.test;

import java.lang.reflect.Proxy;

import neusoft.proxy.dao.MyProxy;
import neusoft.proxy.impl.CountProxy;
import neusoft.proxy.impl.MyDynamicProxy;
import neusoft.proxy.impl.MyProxyImpl;

public class MyDynamicProxyTest {

    public static void main(String[] args) {
        //得到MyProxy接口的一个实例对象.
     MyProxy impl=new MyProxyImpl();
        /*
         * 在java中实现动态代理步骤:
         * 1,由前面的静态代理可知,有一个接口,一个接口的实现类,而这个实现类就是我们要代理的对象。
         * 所谓代理就是在调用实现类的方法时,可以在方法执行前后做额外的工作,这个就是代理。
         * 2,我们要自己写一个在要代理类的方法执行时,能够做额外工作的类,而这个类必须继承InvocationHandler接口,
         * 为什么要继承它呢?因为代理类的实例在调用实现类的方法的时候,不会调真正的实现类的这个方法,
         * 而是转而调用这个类的invoke方法(继承时必须实现的方法),在这个方法中你可以调用真正的实现类的这个方法。
                   在要用代理类的实例去调用实现类的方法的时候,写出下面两段代码。
         */


     MyProxy proxy=(MyProxy)Proxy.newProxyInstance(impl.getClass().getClassLoader(),
                                                   impl.getClass().getInterfaces(),
                                                   new MyDynamicProxy(impl));
                /*
         * 第一,根据impl.getClass().getClassLoader()这个要代理类的类加载器和
         * impl.getClass().getInterfaces()要代理类所实现的所有的接口 impl.getClass().getInterfaces()=new Class[]{MyProxy.class};
         * 作为参数调用Proxy.getProxyClass(ClassLoader loader, Class<?>... interfaces)
         * 的方法返回代理类的java.lang.Class对象,也就是得到了java动态生成的代理类$Proxy0的Class对象。
         * 同时,java还让这个动态生成的$Proxy0类实现了要代理类的实现的所有接口,并继承了Proxy接口。
         * 第二,实例化这个动态生成的$Proxy0类的一个实例,实例化代理类的构造函数为Proxy(InvocationHandler h),
         * 也就是说要实例化这个动态生成的$Proxy0类,必须给它一个InvocationHandler参数,也就是我们自己实现的用来在代理类
         * 方法执行前后做额外工作的类MyDynamicProxy。
         * 这段代码Proxy.newProxyInstance(impl.getClass().getClassLoader(),impl.getClass().getInterfaces(),new MyDynamicProxy(impl))
         * 得到的其实是一个类名叫$Proxy0 extends Proxy implements MyProxy的类。
         * 第三,将这个$Proxy0类强制转型成MyProxy类型,调用add方法。
         */


        proxy.add();
        proxy.delete();
    }

}

输出结果:
add方法执行*****doBefore******
$Proxy0
-----add方法---------------


接口加上delete方法后,输出结果:
add方法执行*****doBefore******
$Proxy0
-----add方法---------------
delete方法执行*****doBefore******
$Proxy0
-----delete方法----

可以看到我们自己加的代理业务逻辑执行了2遍。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值