Java 反射机制与动态代理的两种实现方式

一、谈谈java反射机制:

       java反射机制是一种程序运行时自省的机制,提供了在程序运行时动态的操作任何对象的属性和方法的能力。这样不同创建对象,就可以直接调用其中的任意方法。或者动态的获取某个对象的任意属性。而不用在代码中显示的操作属性,增加的程序的灵活性。

二、JAVA反射API:

         1、Class类

         2、Field类 :通过clazz 对象获取当前类的属性。

         3、Method类:通过clazz 对象获取当前类的方法。

         4、Constructor类等  :

 获取Class对象的方法有:

      创建的对象直接 .getClass()。 

      通过类名.class 获取累的class属性。 

     调用Class类的.forName("全路径名")方法。

三、动态的创建对象:

public class MainTest {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        Class clazz = Person.class;

        // 1、反射创建对象
        //需要有默认空构造器
        Person person1 = clazz.newInstance();
        person1.setAge(25);
        person1.setName("gaocai");
        //根据参数类型返回构造方法,调用构造器的newInstabnce()方法
        Constructor constructor = clazz.getConstructor(String.class, Integer.class);
        Person person2 = constructor.newInstance("gaocai", 25);

        //2、反射获取public属性值 getField()  反射获取private属性值 getDeclaredField()
        Field field = clazz.getDeclaredField("name");
        // 将私有属性放开权限
        field.setAccessible(true);
        Object name = field.get(person1);
        System.out.println("name = " + name);
        field.set(person1, "张三");

        //3、动态的执行public方法 getMethod()  动态的执行public方法 getDeclaredMethod()
        Method getPerson = clazz.getDeclaredMethod("getPerson");
        // 将私有方法放开权限
        getPerson.setAccessible(true);
        Object invoke = getPerson.invoke(person1);
        System.out.println("invoke = " + invoke);
    }
    public static class Person {
        private String name;
        private Integer age;
        public Person() {
        }
        public Person(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
        public void setName(String name) {
            this.name = name;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        private String getPerson() {
            return name +","+ age;
        }
    }
}

Java 反射机制与动态代理的两种实现方式_第1张图片

 

动态代理是java中的一直动态的创建代理对象,并通过代理的方式来对指定的方法进行增强的一直机制。很多场景都是利用类似机制做到的,比如用来包装 RPC 调用、日志、用户鉴权、全局性异常处理、性能监控,甚至事务处理等。实现动态代理的方式很多,比如 JDK 自身提供的动态代理,就是主要利用了上面提到的反射机制。还有其他的实现方式,比如利用传说中更高性能的字节码操作机制,类似 ASM、cglib(基于 ASM)、Javassist 等。

jdk动态代理:自身提供的动态代理要求被代理对象必须实现接口,才可以使用Proxy.newProxyInstance()方法来实现代理。并实现InvocationHandler接口

接口。

cglib动态代理:代理对象不需要实现接口,但是要求代理对象不是final修饰的,cglib采取的是创建目标类的子类的方式,因为是子类化,我们可以达到近似使用被调用者本身的效果。  使用的是Enhancer.create()方法 并实现MethodInterceptor接口。

四、jdk 动态代理:

 

jdk的动态代理用到的类是在java.lang.reflect 包下。如Proxy ,invocationHandler ,Method 等

样本代码:

public interface Person {
    void eat(String food);
}
public class PersonImpl implements Person {
    @Override
    public void eat(String food) {
        System.out.println("我要吃什么呢?" + food);
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class PersonProxyHandler implements InvocationHandler {
    public PersonProxyHandler(T object) {
        this.target = object;
    }
    private final T target;
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //1、invocationHandler 是對代理對象的所有方法进行增强 , 需要放过没有增强的方法
 
        Object invoke = null;
        //2、要么对指定的方法进行增强,放过其他的方法。
        if (method.getName() == "eat") {
            System.out.println("方法前");
            invoke = method.invoke(target, args);
            System.out.println("方法后");
        } else {
            invoke = method.invoke(target, args);
        }
        return invoke;
    }
}
public static void main(String[] args) {
    Person p = new PersonImpl();
    PersonProxyHandler h = new PersonProxyHandler(p);
    Person personProxy = (Person)Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), PersonImpl.class.getInterfaces(), h);
    personProxy.eat("水果");
}

五、cglib 动态代理:

 

public class CglibPerson {

    public void eat(String food) {
        System.out.println("我要吃什么呢?" + food);
    }

    public void sing() {
        System.out.println("我在唱歌");
    }
}
public void cglibProxyTests() {
    CglibPerson person = new CglibPerson();

    CglibPerson proxyPerson = (CglibPerson) Enhancer.create(person.getClass(), new MethodInterceptor() {
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            Object invoke = null;
            if ("eat" == method.getName()) {
                System.out.println("方法前");
                invoke = method.invoke(person, objects);
                System.out.println("方法后");

            } else {
                invoke = method.invoke(person, objects);
            }
            return invoke;
        }
    });
    proxyPerson.eat("食物");
    proxyPerson.sing();

}

 

你可能感兴趣的:(Java,反射)