精华内容
下载资源
问答
  • 主要讲述Java反射机制与设计模式之一:代理模式的原理与应用;同时详细讲述了Java对代理模式的支持以及Java中动态代理的原理,应用与实践。
  • java反射机制和动态代理的原理,熟悉反射机制和动态代理
  • 简单易懂的例子,让你瞬间明白反射和代理的原理
  • )先来一段百度百科的关于反射的定义:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性方法;对于任意一个对象,都能够调用它的任意方法属性;这种动态获取信息以及动态调用对象方法的...

    (之前这篇文章写过了,不知道为什么发表的时候报了404错误,导致心情不好,又重新写的。)

    先来一段百度百科的关于反射的定义:

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

    JAVA反射(放射)机制:"程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言"。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods

    在java中反射是很重要的,在现在的很多框架中也都运用了反射的概念,比如spring中的aop机制就是利用反射原理,动态代理,其实说起动态代理就必须要说反射。在写java我们使用对象的时候一般都是使用new的方式来创建对象,这些将要在程序中使用的对象在编译期间都已经知道了,但是编译期间和运行期间还不一样。假如有类Person,Student类extends了Person(都有空构造函数),Person person=new Stuednt();在编译的时候person是Person类型的,但是在运行的时候确实Student的,有时候我们在程序运行期间根据类去生成相应的对象然后进行一系列的操作,这就是反射,所谓的反射个人理解就是在JVM运行期间通过查找到相应的类,通过类获取其属性以及方法来创造对象。

    通过反射创造类的方式有一下方式:

    有类Person

    package com.tlc.Person;

    public class Person{

    private String name;

    private String sex;

    private Integer age;

    public Person(){};

    public Person(String name,String sex,Integer age){

        this.name=name;

        this.sex=sex;

        this.age=age;

        }

    };

    ①:Person person=new Person();Class clazz=person.getClass();

    ②:Person person=new Person();Class clazz=person.class;

    ③:Class clazz=Class.formName("com.tlc.Person");

    前两种都是通过获取对象的方式来获取Class类,在实际中假如需要使用反射一般都不会使用前两种,而是使用第三种的Class的静态方法来获取。

    获取到class对象之后可以创建实例,查看源码可以知道使用newInstance()或者newInstance(Object....params)分别介绍一下这两种方式,如果没有那种必须要在构造函数中初始化数据的要求,一般使用newInstance()即可够用。

    ①:使用newInstance()方式类中必须要有默认的空构造函数或者显示的空构造函数Person person=(Person)clazz.newInstance(),如果没有空的构造函数会报错。

    ②:使用带参数的构造函数必须要获取到对应的构造函数,这里给大家推荐另外一篇博文:获取构造函数

    Constructor constructor=clazz.getConstructor(Class<?>...ParametersType),必须要有这种参数顺序的构造函数否则就会这偶不到报错,Person person=constructor.newInstance()或者通过有参构造函数来获取即Person person=constructor.newInstance(name,sex,age);对于对象的操作肯定就是对属性的赋值和读取操作了,这时候就要获取其filed,可以通过如下的操作的方式获取以及操作filed,参考此篇博文:操作类的field

    展开全文
  • Java反射机制和动态代理实例

    千次阅读 2016-12-09 09:19:21
    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。 Java...

    反射机制是Java语言的一个重要特性,允许用户动态获取类的信息和动态调用对象的方法。

    通过给定类的名字,通过反射机制就可以获取类的所有信息。

    JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
    Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

    参考案例如下:

    package com.reflect;
    
    public interface CalculatorProtocol {
    	//定义个接口协议
    	public int add(int a,int b);//两个数相加
    	public int subtract(int a,int b);//两个数相减
    }
    
    package com.reflect;
    
    public class Server implements CalculatorProtocol{
    	public int add(int a,int b){
    		return a+b;
    	}
    	public int subtract(int a,int b){
    		return a-b;
    	}
    }
    

    package com.reflect;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class CalculatorHandler implements InvocationHandler, net.sf.cglib.proxy.InvocationHandler{
    	//实现调用处理器接口
    	private Object objOriginal;
    	
    	public CalculatorHandler(Object obj){
    		this.objOriginal=obj;
    	}
    	
    	public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
    		//此处添加预处理
    		Object result=method.invoke(this.objOriginal, args);
    		//此处添加后续处理
    		return result;
    	}
    }
    

    package com.reflect;
    
    import java.lang.reflect.InvocationHandler;
    
    import net.sf.cglib.proxy.Proxy;
    
    public class DynamicProxyExample {
    	public static void main(String[] args){
    		CalculatorProtocol server = new Server();//创建server
    		InvocationHandler handler=new CalculatorHandler(server);
    		CalculatorProtocol client=(CalculatorProtocol)Proxy.newProxyInstance(
    				server.getClass().getClassLoader(),
    				server.getClass().getInterfaces(), 
    				(net.sf.cglib.proxy.InvocationHandler) handler);
    		//创建client
    		int r=client.add(5, 3);
    		System.out.println("5+3="+r);
    		r=client.subtract(5, 3);
    		System.out.println("5-3="+r);
    	}
    }
    




    展开全文
  • 在学习了Java动态代理机制后,我们在本节中将学习Java动态代理机制在Spring中的应用。首先我们创建一个名为AopHandler的类,该类可生成代理对象,同时可以根据设置的前置或后置处理对象分别在方法执行前后执行...
    一.AOP概述
    AOP(Aspect Oriented Programing),即面向切面编程,它主要用于日志记录、性能统计、安全控制、事务处理、异常处理等方面。它的主要意图就要将日志记录,性能统计,安全控制、事务处理、异常处理等等代码从业务逻辑代码中清楚地划分出来。通过对这些行为的分离,我们希望可以将它们独立地配置到业务逻辑方法中,而要改变这些行为的时候也不需要影响到业务逻辑方法代码。
    下面让我们来看一个利用AOP来实现日志记录的例子,在没有使用AOP之前,我们的代码如下面所讲述。
    下面这段代码为业务的接口类代码:

    package org.amigo.proxy;
    /**
    * 业务逻辑类接口.
    * @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
    * Creation date: 2007-10-7 - 上午09:09:53
    */
    public interface BusinessObj {
    /**
    * 执行业务.
    */
    public void process();
    }
    BusinessObj接口的某个实现类代码如下:
    package org.amigo.proxy;
    /**
    * 业务逻辑对象实现类.
    * @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
    * Creation date: 2007-10-7 - 上午09:11:49
    */
    public class BusinessObjImpl implements BusinessObj {
    /**
    * 执行业务.
    */
    public void process() {
    try {
    System.out.println("before process");
    System.out.println("执行业务逻辑");
    System.out.println("after process");
    } catch (Exception e) {
    System.err.println("发生异常:" + e.toString());
    }
    }
    }

    在上例中我们可以看到,在执行业务方法前、执行业务方法后以及异常发生时的日志记录,我们都是通过在对应的类中写入记录日志的代码来实现的,当有这种日志记录需求的业务逻辑类不断增多时,将会给我们的维护带来很大困难,而且,在上面的例子中,日志代码和业务逻辑代码混合在一起,为日后的维护工作又抹上了一层“恐怖”色彩。
    按照AOP的思想,我们首先需要寻找一个切面,在这里我们已经找到,即在业务逻辑执行前后以及异常发生时,进行相应的日志记录。我们需要将这部分日志代码放入一个单独的类中,以便为以后的修改提供方便。
    我们在截获某个业务逻辑方法时,可以采用Java的动态代理机制来实现。在下节中我们将重点讲述Java的动态代理机制。
    复制代码

     

    复制代码
    二.Java的动态代理机制
    代理模式是常用的Java设计模式。代理类主要负责为委托类预处理消息、过滤信息、把消息转发给委托类,以及事后处理信息等。
    动态代理类不仅简化了编程工作,而且提高了软件系统的扩展性和可维护性。我们可以通过实现java.lang.reflect.InvocationHandler接口提供一个执行处理器,然后通过java.lang.reflect.Proxy得到一个代理对象,通过这个代理对象来执行业务逻辑方法,在业务逻辑方法被调用的同时,自动调用会执行处理器。
    下面让我们来创建一个日志拦截器类LogInterceptor.java文件,该类实现java.lang.reflect.InvocationHandler接口,其内容如下所示:

    package org.amigo.proxy;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    /**
    * 日志拦截器,用来进行日志处理.
    *
    @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
    * Creation date: 2007-10-7 - 上午09:31:44
    */
    public class LogInterceptor implements InvocationHandler {
    private Object delegate;
    /**
    * 构造函数,设置代理对象.
    */
    public LogInterceptor(Object delegate){
    this.delegate = delegate;
    }
    /**
    * 方法的调用.
    *
    @param proxy
    *
    @param method 对应的方法
    *
    @param args 方法的参信息
    *
    @return 返回操作结果对象
    *
    @throws Throwable
    */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    Object result = null;
    try {
    System.out.println("before process" + method);
    //调用代理对象delegate的method方法,并将args作为参数信息传入
    result = method.invoke(delegate, args);
    System.out.println("after process" + method);
    } catch (Exception e){
    System.err.println("发生异常:" + e.toString());
    }
    return result;
    }
    /**
    * 测试方法.
    *
    @param args
    *
    @throws Exception
    */
    public static void main(String[] args) throws Exception {
    BusinessObj obj = new BusinessObjImpl();
    //创建一个日志拦截器
    LogInterceptor interceptor = new LogInterceptor(obj);
    //通过Proxy类的newProxyInstance(...)方法来获得动态的代理对象
    BusinessObj proxy = (BusinessObj) Proxy.newProxyInstance(
    BusinessObjImpl.class.getClassLoader(),
    BusinessObjImpl.class.getInterfaces(),
    interceptor);
    //执行动态代理对象的业务逻辑方法
    proxy.process();
    }
    }

    此时还需要对BusinessObj的实现类BusinessObjImpl类进行修改,去掉其日志记录等内容,修改后的文件如下:

    package org.amigo.proxy;
    /**
    * 业务逻辑对象实现类.
    *
    @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
    * Creation date: 2007-10-7 - 上午09:11:49
    */
    public class BusinessObjImpl implements BusinessObj {
    /**
    * 执行业务.
    */
    public void process() {
    System.out.println("执行业务逻辑");
    }
    }

    运行LogInterceptor类我们可以发现,它实现了前面所需要的功能,但是很好的将业务逻辑方法的代码和日志记录的代码分离开来,并且所有的业务处理对象都可以利用该类来完成日志的记录,防止了重复代码的出现,增加了程序的可扩展性和可维护性,从而提高了代码的质量。那么Spring中的AOP的实现是怎么样的呢?接着让我们来对Spring的AOP进行探讨,了解其内部实现原理。
    复制代码


    复制代码
    三.Spring中AOP的模拟实现
    在学习了Java的动态代理机制后,我们在本节中将学习Java的动态代理机制在Spring中的应用。首先我们创建一个名为AopHandler的类,该类可生成代理对象,同时可以根据设置的前置或后置处理对象分别在方法执行前后执行一些另外的操作,该类的内容如下所示:

    package org.amigo.proxy;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    /**
    * AOP处理器.
    *
    @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
    * Creation date: 2007-10-7 - 上午10:13:28
    */
    public class AopHandler implements InvocationHandler {
    //需要代理的目标对象
    private Object target;
    //方法前置顾问
    Advisor beforeAdvisor;
    //方法后置顾问
    Advisor afterAdvisor;
    /**
    * 设置代理目标对象,并生成动态代理对象.
    *
    @param target 代理目标对象
    *
    @return 返回动态代理对象
    */
    public Object setObject(Object target) {
    //设置代理目标对象
    this.target = target;
    //根据代理目标对象生成动态代理对象
    Object obj = Proxy.newProxyInstance(
    target.getClass().getClassLoader(),
    target.getClass().getInterfaces(), this);
    return obj;
    }
    /**
    * 若定义了前置处理,则在方法执行前执行前置处理,
    * 若定义了后置处理,则在方法调用后调用后置处理.
    *
    @param proxy 代理对象
    *
    @param method 调用的业务方法
    *
    @param args 方法的参数
    *
    @return 返回结果信息
    *
    @throws Throwable
    */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    //进行业务方法的前置处理
    if (beforeAdvisor != null) {
    beforeAdvisor.doInAdvisor(proxy, method, args);
    }
    //执行业务方法
    Object result = method.invoke(target, args);
    //进行业务方法的后置处理
    if (afterAdvisor != null) {
    afterAdvisor.doInAdvisor(proxy, method, args);
    }
    //返回结果对象
    return result;
    }
    /**
    * 设置方法的前置顾问.
    *
    @param advisor 方法的前置顾问
    */
    public void setBeforeAdvisor(Advisor advisor) {
    this.beforeAdvisor = advisor;
    }
    /**
    * 设置方法的后置顾问.
    *
    @param advisor 方法的后置顾问
    */
    public void setAfterAdvisor(Advisor advisor) {
    this.afterAdvisor = advisor;
    }
    }

    在上类中,前置和后置顾问对象都继承Advisor接口,接下来让我们来看看顾问接口类的内容,该类定义了doInAdvisor(Object proxy, Method method, Object[] args)方法,如下所示:
    package org.amigo.proxy;
    import java.lang.reflect.Method;
    /**
    *
    * 顾问接口类.
    *
    @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
    * Creation date: 2007-10-7 - 上午10:21:18
    */
    public interface Advisor {
    /**
    * 所做的操作.
    */
    public void doInAdvisor(Object proxy, Method method, Object[] args);
    }
    BeforeMethodAdvisor和AfterMethodAdvisor都实现了Advisor接口,分别为方法的前置顾问和后置顾问类。
    BeforeMethodAdvisor.java文件(前置顾问类)的内容如下所示:
    package org.amigo.proxy;
    import java.lang.reflect.Method;
    /**
    *
    * 方法前置顾问,它完成方法的前置操作.
    *
    @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
    * Creation date: 2007-10-7 - 上午10:19:57
    */
    public class BeforeMethodAdvisor implements Advisor {
    /**
    * 在方法执行前所进行的操作.
    */
    public void doInAdvisor(Object proxy, Method method, Object[] args) {
    System.out.println("before process " + method);
    }
    }
    AfterMethodAdvisor.java文件(后置顾问类)的内容如下所示:
    package org.amigo.proxy;
    import java.lang.reflect.Method;
    /**
    *
    * 方法的后置顾问,它完成方法的后置操作.
    *
    @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
    * Creation date: 2007-10-7 - 上午10:20:43
    */
    public class AfterMethodAdvisor implements Advisor {
    /**
    * 在方法执行后所进行的操作.
    */
    public void doInAdvisor(Object proxy, Method method, Object[] args) {
    System.out.println("after process " + method);
    }
    }

    这两个类分别在方法执行前和方法执行后做一些额外的操作。
    对于在配置文件中对某个bean配置前置或后置处理器,我们可以在bean中增加两个属性aop和aopType,aop的值为对应的前置顾问类或后置顾问类的名称,aopType用于指明该顾问类为前置还是后置顾问,为before时表示为前置处理器,为after时表示为后置处理器,这时候我们需要修改上一篇文章中的BeanFactory.java这个文件,添加其对aop和aopType的处理,修改后的该文件内容如下:

    package org.amigo.proxy;
    import java.io.InputStream;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    import org.dom4j.Attribute;
    import org.dom4j.Document;
    import org.dom4j.Element;
    import org.dom4j.io.SAXReader;
    /**
    * bean工厂类.
    *
    @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a>
    * Creation date: 2007-10-7 - 下午04:04:34
    */
    public class BeanFactory {
    private Map<String, Object> beanMap = new HashMap<String, Object>();
    /**
    * bean工厂的初始化.
    *
    @param xml xml配置文件
    */
    public void init(String xml) {
    try {
    //读取指定的配置文件
    SAXReader reader = new SAXReader();
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    InputStream ins = classLoader.getResourceAsStream(xml);
    Document doc = reader.read(ins);
    Element root = doc.getRootElement();
    Element foo;
    //创建AOP处理器
    AopHandler aopHandler = new AopHandler();
    //遍历bean
    for (Iterator i = root.elementIterator("bean"); i.hasNext();) {
    foo = (Element) i.next();
    //获取bean的属性id、class、aop以及aopType
    Attribute id = foo.attribute("id");
    Attribute cls = foo.attribute("class");
    Attribute aop = foo.attribute("aop");
    Attribute aopType = foo.attribute("aopType");
    //配置了aop和aopType属性时,需进行拦截操作
    if (aop != null && aopType != null) {
    //根据aop字符串获取对应的类
    Class advisorCls = Class.forName(aop.getText());
    //创建该类的对象
    Advisor advisor = (Advisor) advisorCls.newInstance();
    //根据aopType的类型来设置前置或后置顾问
    if ("before".equals(aopType.getText())) {
    aopHandler.setBeforeAdvisor(advisor);
    } else if ("after".equals(aopType.getText())) {
    aopHandler.setAfterAdvisor(advisor);
    }
    }
    //利用Java反射机制,通过class的名称获取Class对象
    Class bean = Class.forName(cls.getText());
    //获取对应class的信息
    java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean);
    //获取其属性描述
    java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors();
    //设置值的方法
    Method mSet = null;
    //创建一个对象
    Object obj = bean.newInstance();
    //遍历该bean的property属性
    for (Iterator ite = foo.elementIterator("property"); ite.hasNext();) {
    Element foo2 = (Element) ite.next();
    //获取该property的name属性
    Attribute name = foo2.attribute("name");
    String value = null;
    //获取该property的子元素value的值
    for(Iterator ite1 = foo2.elementIterator("value"); ite1.hasNext();) {
    Element node = (Element) ite1.next();
    value = node.getText();
    break;
    }
    for (int k = 0; k < pd.length; k++) {
    if (pd[k].getName().equalsIgnoreCase(name.getText())) {
    mSet = pd[k].getWriteMethod();
    //利用Java的反射极致调用对象的某个set方法,并将值设置进去
    mSet.invoke(obj, value);
    }
    }
    }
    //为对象增加前置或后置顾问
    obj = (Object) aopHandler.setObject(obj);
    //将对象放入beanMap中,其中key为id值,value为对象
    beanMap.put(id.getText(), obj);
    }
    } catch (Exception e) {
    System.out.println(e.toString());
    }
    }
    /**
    * 通过bean的id获取bean的对象.
    *
    @param beanName bean的id
    *
    @return 返回对应对象
    */
    public Object getBean(String beanName) {
    Object obj = beanMap.get(beanName);
    return obj;
    }
    /**
    * 测试方法.
    *
    @param args
    */
    public static void main(String[] args) {
    BeanFactory factory = new BeanFactory();
    factory.init("config.xml");
    BusinessObj obj = (BusinessObj) factory.getBean("businessObj");
    obj.process();
    }
    }

    观察此类我们可以发现,该类添加了对bean元素的aop和aopType属性的处理。编写完该文件后,我们还需要修改src目录下的配置文件:config.xml文件,在该文件中添加名为businessObj的bean,我们为其配置了aop和aopType属性,增加了方法的前置顾问。增加的部分为:

    <bean id="businessObj" class="org.amigo.proxy.BusinessObjImpl" aop="org.amigo.proxy.BeforeMethodAdvisor" aopType="before"/>
    此时运行BeanFactory.java这个类文件,运行结果如下:
    before process public abstract void org.amigo.proxy.BusinessObj.process()
    执行业务逻辑
    由运行结果可以看出,前置处理已经生效。
    本节中的例子只是实现了Spring的AOP一小部分功能,即为某个bean添加前置或后置处理,在Spring中,考虑的比这多很多,例如,为多个bean配置动态代理等等。但是究其根源,Spring中AOP的实现,是基于Java中无比强大的反射和动态代理机制。

    四.总结
    本文讲述了AOP的概念等信息,并详细讲解了Java的动态代理机制,接着又通过一个简单的实例讲解了Spring中AOP的模拟实现,使得读者能够更好地学习Java的反射和代理机制。
    通过这两篇文章,使得我们能够更加深入地理解Java的反射和动态代理机制,同时对Spring中盛行的IOC和AOP的后台实现原理有了更加清晰的理解,Java的反射和动态代理机制的强大功能在这两篇文章中可见一斑。有兴趣的朋友可以通过学习Spring框架的源码来进一步的理解Java的反射和动态代理机制,从而在实际的开发工作中更好地理解它。
    展开全文
  • java反射机制动态代理java反射机制动态代理
  • Java反射机制动态代理 浪曦 Java Reflection API 简介 及动态代理
  • 在介绍过滤器Filter拦截器Interceptor之前,先大篇幅介绍下Java反射机制和动态代理(本来想着只是简单说明下这两个名称,但下笔介绍过程中发现对反射机制和动态代理一知半解,随进行了深入了解源码剖析),动态...

    在介绍过滤器Filter和拦截器Interceptor之前,先大篇幅介绍下Java反射机制和动态代理(本来想着只是简单说明下这两个名称,但下笔介绍过程中发现对反射机制和动态代理一知半解,随进行了深入了解和源码剖析),动态代理主要使用了Java凡是机制来实现,而拦截器Interceptor又是通过动态代理实现的。

    一、Java反射机制

    在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取的信息以及动态调用对象方法的功能成为Java的反射机制。

    反射就是把Java类中的各种成分映射成一个个的Java对象。例如一个类中有成员变量、方法、构造方法、包等信息,利用反射机制可以对一个类进行解剖,把类的组成部分映射成一个个对象。反射可以在程序运行过程中动态获取类的相关信息,包括类由哪个类加载器进行加载,类中的成员变量,成员方法,访问修饰符,返回值类型,构造方法等。

    举例说明JAVA的反射机制的几个主要功能,(1)在运行时判断任意一个对象所属的类obj.getClass()。(2)在运行时构造任意一个类的对象constructor.newInstance(new Object[]{h})。(3)在运行时判断任意一个类所具有的成员变量和方法getDeclaredFields()、getDeclaredMethods()。

    二、动态代理

    代理模式为其它对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

    动态代理是指客户通过代理类来调用其它对象的方法,主要使用了Java反射机制来实现动态代理。使用Java的反射机制创建动态代理对象,让代理对象在调用目标方法之前和之后分别做一些事情,然后动态代理对象决定是否调用以及何时来调用被代理对象的方法。

    Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类。

    (1)InvocationHandler:该接口中仅定义了一个方法 public object invoke(Object proxy,Method method, Object[] args),其中第一个参数proxy是代理类的实例,method是被代理的方法,即需要执行的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。

    (2)Proxy:该类即为动态代理类。

    动态代理的步骤

    (1)创建一个实现接口InvocationHandler的类,它必须实现invoke方法;

    (2)创建被代理的接口以及实现类;

    (3)通过Proxy的静态方法

    newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个代理;

    (4)通过代理调用方法。

    先通过一段代码看看动态代理是怎么实现的:

    public class DynamicProxy {
    	public static void main(String[] args) throws Exception {
            // 被代理对象,其中Subject为接口,SubjectImpl为接口实现类
            Subject target = new SubjectImpl();
            // 动态生成的代理对象
            // target.getClass().getInterfaces()和Java的反射机制有关,它能够获得这个对象所实现的接口
            Subject porxy = (Subject)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            	@Override
            	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            		System.out.println("方法调用前~~");
            		Object temp = method.invoke(target, args);
            		System.out.println("方法调用后~~");
                    return temp;
            	}
            });
            // 通过代理对象执行方法say
            porxy.say("wangpf", 20);
        }
    }

    下面通过简单剖析Proxy源码分析下动态代理是怎么实现的,通过上面代码发现代理对象是Proxy通过静态方法newProxyInstance生成的,那么先看下这个核心方法。它有三个参数:类加载器loader,被代理对象实现的接口interfaces,接口InvocationHandler。接着通过添加注释的方式剖析下这个核心方法。

    @CallerSensitive
        public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException
        {
    	// 检查 h 不为空,否则抛异常
            Objects.requireNonNull(h);
    
            // 对传入的接口做安全检查
            final Class<?>[] intfs = interfaces.clone();
            final SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
            }
    
            /*
             * Look up or generate the designated proxy class.
             */
            // 根据指定接口生成代理类,如果实现了给定接口的代理类已经存在,则生成一个copy直接返回,否则通过ProxyClassFactory生成一个代理类。
            Class<?> cl = getProxyClass0(loader, intfs);
    
            /*
             * Invoke its constructor with the designated invocation handler.
             */
            try {
                if (sm != null) {
                    checkNewProxyPermission(Reflection.getCallerClass(), cl);
                }
    
                // 通过类对象的getConstructor()方法获得构造器(Constructor)对象
                final Constructor<?> cons = cl.getConstructor(constructorParams);
                final InvocationHandler ih = h;
                if (!Modifier.isPublic(cl.getModifiers())) {
                    AccessController.doPrivileged(new PrivilegedAction<Void>() {
                        public Void run() {
                            cons.setAccessible(true);
                            return null;
                        }
                    });
                }
                // cons调用其newInstance()方法创建代理对象
                return cons.newInstance(new Object[]{h});
            } catch (IllegalAccessException|InstantiationException e) {
                throw new InternalError(e.toString(), e);
            } catch (InvocationTargetException e) {
                Throwable t = e.getCause();
                if (t instanceof RuntimeException) {
                    throw (RuntimeException) t;
                } else {
                    throw new InternalError(t.toString(), t);
                }
            } catch (NoSuchMethodException e) {
                throw new InternalError(e.toString(), e);
            }
        }

    不难发现上述源码中核心代码为Class<?> cl = getProxyClass0(loader, intfs),当代理类不存在时需要由ProxyClassFactory生成一个新的代理类,下面看看另一个重要内部类Proxy.ProxyClassFactory是怎样生成代理类的(由于代理较多,这里只截取部分代码说明)。

    /**
         * A factory function that generates, defines and returns the proxy class given
         * the ClassLoader and array of interfaces.
         */
        private static final class ProxyClassFactory
            implements BiFunction<ClassLoader, Class<?>[], Class<?>>
        {
            // prefix for all proxy class names
            private static final String proxyClassNamePrefix = "$Proxy";
    
            // next number to use for generation of unique proxy class names
            private static final AtomicLong nextUniqueNumber = new AtomicLong();
    
            @Override
            public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
            	// 此处省略N行代码
                /*
                 * Choose a name for the proxy class to generate.
                 */
                // proxyPkg 为动态代理类的包名,如果接口类是非public修饰符,采用和接口类相同包名,否则使用包名com.sun.proxy。
                // proxyName 为代理类的完全限定名
                long num = nextUniqueNumber.getAndIncrement();
                String proxyName = proxyPkg + proxyClassNamePrefix + num;
    
                /*
                 * Generate the specified proxy class.
                 */
                // 根据代理类名称生成代理类class文件的byte数组。
                byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
                    proxyName, interfaces, accessFlags);
                try {
                	// 加载代理类,返回代理类Class对象
                    return defineClass0(loader, proxyName,
                                        proxyClassFile, 0, proxyClassFile.length);
                } catch (ClassFormatError e) {
                    throw new IllegalArgumentException(e.toString());
                }
            }
        }

    三、过滤器Filter和拦截器Interceptor的区别

    关于过滤器Filter和拦截器Interceptor的区别,这里借用网友一张图进行说明。

    (1)过滤器是基于函数回调,而拦截器是基于Java反射机制动态代理;

    (2)过滤器是servlet规范规定的,只能用于Web程序中,而拦截器是在spring容器中,不依赖servlet容器;

    (3)过滤器不能访问action上下文及值栈里的对象,而拦截器都可以;

    (4)过滤器只在容器初始化时被调用一次,而拦截器在action生命周期内可以多次调用;

    (5)拦截器被包裹在过滤器之中。

    展开全文
  • JAVA反射机制动态代理 介绍java的反射机制和动态代理
  • 清晰描述java反射机制和动态代理的关系
  • JAVA反射机制动态代理.part09
  • JAVA反射机制动态代理.part08
  • JAVA反射机制动态代理.part07
  • JAVA反射机制动态代理.part06
  • JAVA反射机制动态代理.part05
  • JAVA反射机制动态代理.part04
  • JAVA反射机制动态代理.part03
  • JAVA反射机制动态代理.part02
  • JAVA反射机制动态代理.part01
  • JAVA 反射机制动态代理ppt,郎溪出品
  • 这是很全的关于java反射动态代理方面的书,并且配有源代码,在平台框架开发方面会经常用得着

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 63,010
精华内容 25,204
关键字:

java反射机制和动态代理

java 订阅