Java动态代理学习

动态代理类

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

  1.Interface InvocationHandler

  该接口中仅定义了一个方法:

  Object invoke(Object proxy, Method method, Object[] args) 

  在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组(无参时设置为null)。

  这个抽象方法在代理类中动态实现。

  2.Proxy

  该类即为动态代理类,作用类似于上文例子中的ProxySubject,其中主要包含如下内容:

  protected  Proxy(InvocationHandler h): 构造函数,用于给内部的invocation handler赋值。

  static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) : loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

  static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)  :返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类在Subject接口中声明过的方法)。

 

动态代理类说明

  所谓Dynamic Proxy是这样一种class:

  它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。

  你当然可以把该class的实例当作这些interface中的任何一个来用。

  当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你做实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

  在使用动态代理类时,我们必须实现InvocationHandler接口。每一个动态代理类都会有一个与之关联的invocation handler。

  真正的调用是在invocation handler的invoke()方法里完成的。

 

动态代理步骤

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

  2.创建被代理的类以及接口。

  3.通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)创建一个代理。

  4.通过代理调用方法。

动态代理例子1:

  首先定义抽象角色和真实角色类:

public interface Subject
{
    public void request();
}
复制代码
public class RealSubject implements Subject
{
    @Override
    public void request()
    {
        System.out.println("From real subject!");
    }
}
复制代码

  之后定义一个DynamicSubject类:

复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 该代理类的内部属性是Object类型,实际使用的时候通过该类的构造方法传递进来一个对象。
 * 该类实现了invoke()方法,该方法中的method.invoke()其实就是调用被代理对象的将要执行的方法,
 * 方法参数sub表示该方法从属于sub。
 * 通过动态代理类,我们可以在执行真实对象的方法前后加入自己的一些额外方法
 *
 */
public class DynamicSubject implements InvocationHandler
{

    //对真实对象的引用
    private Object sub;
    
    public DynamicSubject(Object obj)
    {
        this.sub = obj;
        
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable
    {
        System.out.println("Before calling: " + method);
        
        //通过反射来调用方法
        method.invoke(sub, args);
        
        System.out.println("After calling: " + method);
        return null;
    }

}
复制代码

  使用的时候:

复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class Client
{
    public static void main(String[] args)
    {
        RealSubject realSubject = new RealSubject();

        InvocationHandler handler = new DynamicSubject(realSubject);

        Class<?> classType = handler.getClass();

        // 生成代理
        // 动态生成一个类(实现了指定的接口),生成类的对象,转换成接口类型
        Subject subject = (Subject) Proxy.newProxyInstance(classType
                .getClassLoader(), realSubject.getClass().getInterfaces(),
                handler);

        subject.request();
        // 调用方法时,转移给handler接管,由其中的invoke()方法实际完成方法执行

        System.out.println(subject.getClass());// 打印出:class $Proxy0
        // $Proxy0是在运行期间动态生成的一个类

    }

}
复制代码

  通过这种方式,被代理的对象(RealSubject)可以在运行时动态改变,需要控制的接口(Subject接口)可以在运行时改变,控制的方式(DynamicSubject类)也可以动态改变,从而实现了非常灵活的动态代理关系。

 

动态代理实现例子2:

  这个例子中定义了一个接口: 

public interface Foo
{
    public void doAction();
}

  这个接口有两个实现类:

复制代码
public class FooImpl1 implements Foo
{
    @Override
    public void doAction()
    {
        System.out.println("From Implement 1 !");
    }
}

public class FooImpl2 implements Foo
{
    @Override
    public void doAction()
    {
        System.out.println("From Implement 2 !");
    }
}
复制代码

  定义invocation handler,其中的set方法使得实际对象是可更换的:

复制代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class CommonInvocationHandler implements InvocationHandler
{
    private Object target;

    public CommonInvocationHandler()
    {

    }

    public CommonInvocationHandler(Object obj)
    {
        this.target = obj;
    }

    public void setTarget(Object target)
    {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable
    {        
        return method.invoke(target, args);
    }

}
复制代码

  使用:

复制代码
import java.lang.reflect.Proxy;

public class Demo
{
    public static void main(String[] args)
    {
        CommonInvocationHandler handler = new CommonInvocationHandler();

        Foo f = null;

        handler.setTarget(new FooImpl1());

        f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
                new Class[] { Foo.class }, handler);
        
        f.doAction();
        System.out.println("----------------------------");
        handler.setTarget(new FooImpl2());    
        f.doAction();

    }

}
复制代码

  程序运行后输出:

From Implement 1 !
----------------------------
From Implement 2 !

 

动态代理实现例子3:

1、BookFacade.java  

 public interface BookFacade {

 public void addBook();  

}  

2、BookFacadeImpl.java   

public class BookFacadeImpl implements BookFacade {  

@Override  

public void addBook() {  

        System.out.println("增加图书方法。。。");  

    }  
}  

3、BookFacadeProxy.java  

  • package net.battier.proxy;  
    import java.lang.reflect.InvocationHandler;  
    import java.lang.reflect.Method;  
    import java.lang.reflect.Proxy;  
    /** 
     * JDK动态代理代理类 
     *  
     * @author student 
     *  
     */  
    public class BookFacadeProxy implements InvocationHandler {  
    private Object target;  
    /** 
         * 绑定委托对象并返回一个代理类 
         * @param target 
         * @return 
         */  
    public Object bind(Object target) {  
    this.target = target;  
    //取得代理对象  
    return Proxy.newProxyInstance(target.getClass().getClassLoader(),  
                    target.getClass().getInterfaces(), this);   //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)  
        }  
    @Override  
    /** 
         * 调用方法 
         */  
    public Object invoke(Object proxy, Method method, Object[] args)  
    throws Throwable {  
            Object result=null;  
            System.out.println("事物开始");  
    //执行方法  
            result=method.invoke(target, args);  
            System.out.println("事物结束");  
    return result;  
        }  
    }  

    4、TestProxy.java 

  • package net.battier.test;  
    import net.battier.dao.BookFacade;  
    import net.battier.dao.impl.BookFacadeImpl;  
    import net.battier.proxy.BookFacadeProxy;  
    public class TestProxy {  
    public static void main(String[] args) {  
            BookFacadeProxy proxy = new BookFacadeProxy();  
            BookFacade bookProxy = (BookFacade) proxy.bind(new BookFacadeImpl());  
            bookProxy.addBook();  
        }  
    }  

但是,JDK的动态代理依靠接口实现,如果有些类并没有实现接口,则不能使用JDK代理,这就要使用cglib动态代理了。 

Cglib动态代理 
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 
示例 
1、BookFacadeCglib.java 

  • package net.battier.dao;  
    public interface BookFacade {  
    public void addBook();  
    }  

2、BookCadeImpl1.java 

  • package net.battier.dao.impl;  
    /** 
     * 这个是没有实现接口的实现类 
     *  
     * @author student 
     *  
     */  
    public class BookFacadeImpl1 {  
    public void addBook() {  
            System.out.println("增加图书的普通方法...");  
        }  
    }  

3、BookFacadeProxy.java 

  • package net.battier.proxy;  
    import java.lang.reflect.Method;  
    import net.sf.cglib.proxy.Enhancer;  
    import net.sf.cglib.proxy.MethodInterceptor;  
    import net.sf.cglib.proxy.MethodProxy;  
    /** 
     * 使用cglib动态代理 
     *  
     * @author student 
     *  
     */  
    public class BookFacadeCglib implements MethodInterceptor {  
    private Object target;  
    /** 
         * 创建代理对象 
         *  
         * @param target 
         * @return 
         */  
    public Object getInstance(Object target) {  
    this.target = target;  
            Enhancer enhancer = new Enhancer();  
            enhancer.setSuperclass(this.target.getClass());  
    // 回调方法  
            enhancer.setCallback(this);  
    // 创建代理对象  
    return enhancer.create();  
        }  
    @Override  
    // 回调方法  
    public Object intercept(Object obj, Method method, Object[] args,  
                MethodProxy proxy) throws Throwable {  
            System.out.println("事物开始");  
            proxy.invokeSuper(obj, args);  
            System.out.println("事物结束");  
    return null;  
        }  
    }  

4、TestCglib.java 

 

package net.battier.test;  
import net.battier.dao.impl.BookFacadeImpl1;  
import net.battier.proxy.BookFacadeCglib;  
public class TestCglib {  
public static void main(String[] args) {  
        BookFacadeCglib cglib=new BookFacadeCglib();  
        BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  
        bookCglib.addBook();  
    }  
}  



 

  

posted @ 2016-07-09 16:35  温暖的向阳花  阅读(177)  评论(0编辑  收藏  举报