Java动态代理和cglib动态代理

1、何为动态代理?html

    建议看动态代理前,先看看反射 点击这里java

  先看一个小案例,假设有咖啡类A,B,C。有添加物类a,b,c,。如今对咖啡类进行加强。( 好比像向啡中加糖,牛奶等这个意思)。程序员

  对一个类进行加强能够有三种方式:spring

  1.继承,能够直接继承父类的属性和方法,在新增本身的属性和方法。那么咱们对每种咖啡进行加强,一共须要写3*3个继承类来完成。加强的对象和内容都不可变。数组

  2.装饰者模式,在须要加强的类中组合一个须要加强的属性。那么咱们须要写三个组合咖啡类,每一个类都添加一个添加物接口属性,向添加物接口传不一样的实现就能够对该咖啡类进行不一样的加强。加强的内容可变,但加强的对象是不可变的。ide

  3.动态代理,经过一个代理工厂,向其传入须要加强的咖啡类和添加物类,其自动生成一个加强后的代理类。咱们只须要实现代理工厂这个类便可。测试

2、java动态代理的实现this

  java中有一个类Proxy,其有一个静态方法Object proxy = Proxy.newProxyInstance(ClassLoader classLoader , Class[] interfaces , InvocationHandler); 经过此方法就能够获得一个代理对象。下面说一下这三个参数。spa

  ClassLoader 类加载器,负责加载代理的类加载器。关于类加载器详细解答 点击这里代理

  Class[] 目标类所实现的接口们,用Class对象数组表示。

  Invocationhandler 处理器,当调用代理类proxy的方法时,其实是调用处理器的 invoke()方法。下面在对invoke方法进行详解。

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

  proxy:代理对象。  method: 执行的代理对象的方法。 args: 调用代理对象的方法时传入的参数。

  下面贴代码实现

目标类接口

package cn.edu;

public interface Waiter {

    public void server();
}

 

前置通知接口

package cn.edu;

public interface AdviceBefore {

    public void before();
}

后置通知接口

package cn.edu;

public interface AdviceAfter {

    public void after();
}

代理工厂

package cn.edu;

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

/**
 * 代理工厂,用于生产代理对象
 * 
 * @author WangHang
 *
 */
public class ProxyFactory {

    private Object target;               // 目标对象

    private AdviceBefore adviceBefore;   // 前置通知

    private AdviceAfter adviceAfter;     // 后置通知

    // 生成代理对象核心方法
    public Object getProxyInstance() {

        ClassLoader loader = ProxyFactory.class.getClassLoader();    // 类加载器
        Class[] interfaces = target.getClass().getInterfaces();      // 类所实现的接口

        InvocationHandler h = new InvocationHandler() {              // 处理器
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (adviceBefore != null) {
                    adviceBefore.before();                           // 调用前置通知
                }
                Object result = method.invoke(target, args);         // 调用目标方法
                if (adviceAfter != null) {                           // 调用后置通知
                    adviceAfter.after();
                }
                return result;
            }
        };

        Object proxy = Proxy.newProxyInstance(loader, interfaces, h); // 经过给定的三个参数生成动态代理对象
        return proxy;                                                 // 返回代理对象
    }

    public AdviceBefore getAdviceBefore() {
        return adviceBefore;
    }

    public void setAdviceBefore(AdviceBefore adviceBefore) {
        this.adviceBefore = adviceBefore;
    }

    public AdviceAfter getAdviceAfter() {
        return adviceAfter;
    }

    public void setAdviceAfter(AdviceAfter adviceAfter) {
        this.adviceAfter = adviceAfter;
    }

    public Object getTarget() {
        return target;
    }

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

}

测试,接口的实现用的匿名内部类

package cn.edu;

import org.junit.Test;

public class ProxyTest {

    @Test
    public void fun() {
        Waiter waiter = new Waiter() {                         //生成目标对象
            @Override
            public void server() {
                System.out.println("服务中。。。");
            }
        };
        
        AdviceBefore before = new AdviceBefore() {             //生成前置通知
            @Override
            public void before() {
                System.out.println("欢迎光临!");
            }
        };
        
        AdviceAfter after = new AdviceAfter() {
            @Override
            public void after() {
                System.out.println("谢谢光临!");                //生成后置通知
            }
        };
        
        ProxyFactory proxyFactory = new ProxyFactory();        //生成工厂
        
        proxyFactory.setTarget(waiter);                          //设置目标对象
        proxyFactory.setAdviceBefore(before);                    //设置前置通知
        proxyFactory.setAdviceAfter(after);                      //设置后置通知
        
        Waiter proxy = (Waiter)proxyFactory.getProxyInstance();  //得到代理对象
        
        proxy.server();                                          //调用目标对象的方法
    }
    
}

运行结果:

3、cglib动态代理的实现

   java动态代理的实现要求目标类实现接口,若是没有接口就没法完成动态代理。cglib(Code Genaration Liarbry)是一个强大的Code生成类库 ,它能够在程序运行期间扩展Java类。它不要求目标类实现接口,它采用的是继承的方式来扩展目标类。

  下面用cglib实现代理,其他类不用变,只需更改代理工厂,而且给Waiter添加一个实现类WaiterImpl,cglib代理是须要类的,用匿名类是会报错的。更改的部分以下。

Waiter实现类

package cn.edu.cglibProxy;

public class WaiterImpl implements Waiter {

    @Override
    public void server() {
        // TODO Auto-generated method stub
        System.out.println("服务中。。。");
    }

}

代理工厂类

package cn.edu.cglibProxy;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

/**
 * 代理工厂,用于生产代理对象
 * 
 * @author WangHang
 *
 */
public class ProxyFactory {

    private Object target;             // 目标对象

    private AdviceBefore adviceBefore; // 前置通知

    private AdviceAfter adviceAfter;   // 后置通知

    // 生成代理对象核心方法
    public Object getProxyInstance() {

        Enhancer enhancer = new Enhancer();
        
        enhancer.setSuperclass(target.getClass());
        
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                adviceBefore.before();
                Object result = method.invoke(target, args);
                adviceAfter.after();
                return result;
            }
        });
        Object proxy = enhancer.create();
        return proxy;            // 返回代理对象
    }

    public AdviceBefore getAdviceBefore() {
        return adviceBefore;
    }

    public void setAdviceBefore(AdviceBefore adviceBefore) {
        this.adviceBefore = adviceBefore;
    }

    public AdviceAfter getAdviceAfter() {
        return adviceAfter;
    }

    public void setAdviceAfter(AdviceAfter adviceAfter) {
        this.adviceAfter = adviceAfter;
    }

    public Object getTarget() {
        return target;
    }

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

}

测试类

package cn.edu.cglibProxy;

import org.junit.Test;

public class ProxyTest {

    @Test
    public void fun() {
        
        Waiter waiter = new WaiterImpl();
        
        AdviceBefore before = new AdviceBefore() {             //生成前置通知
            @Override
            public void before() {
                System.out.println("欢迎光临!");
            }
        };
        
        AdviceAfter after = new AdviceAfter() {
            @Override
            public void after() {
                System.out.println("谢谢光临!");                //生成后置通知
            }
        };
        
        ProxyFactory proxyFactory = new ProxyFactory();        //生成工厂
        
        proxyFactory.setTarget(waiter);                          //设置目标对象
        proxyFactory.setAdviceBefore(before);                    //设置前置通知
        proxyFactory.setAdviceAfter(after);                      //设置后置通知
        
        Waiter proxy = (Waiter)proxyFactory.getProxyInstance();  //得到代理对象
        
        proxy.server();                                          //调用目标对象的方法
    }
    
}

测试结果

 

4、总结  

  经过上面的两个例子,能够体会到动态代理的优点。静态代理是由程序员手动编写好源代码,在程序运行时已经存在了class文件,而动态代理则是在运行时根据须要动态生成的,不只减小了工做量,使用时也更加灵活。

相关文章
相关标签/搜索