java动态代理

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java动态代理相关的知识,希望对你有一定的参考价值。

代理模式:常用的java设计模式,特征是代理类与委托类之间有相同的接口,代理类主要负责为委托类预处理信息、过滤信息、把消息转化给委托类以及事后处理消息等。代理类与委托类之间通常存在关联,代理类的对象并不真正实现服务,而是调用委托类的对象的相关方法提供服务。

按照代理的创建时期,代理类分为:

  静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件已存在了。

  动态代理:在程序运行时,运用反射机制动态创建而成。

 

首先看一下静态代理:

1、Count.java 

  package net.battier.dao;  

  1. public interface Count {  
  2. // 查看账户方法  
  3. public void queryCount();  
  4. // 修改账户方法  
  5. public void updateCount();  
  6. }  


2、CountImpl.java 

  1. package net.battier.dao.impl;  
  2.   
  3. import net.battier.dao.Count;  
  4.   
  5. /** 
  6.  * 委托类(包含业务逻辑) 
  7.  *  
  8.  * @author Administrator 
  9.  *  
  10.  */  
  11. public class CountImpl implements Count {  
  12.   
  13.     @Override  
  14.     public void queryCount() {  
  15.         System.out.println("查看账户方法...");  
  16.   
  17.     }  
  18.   
  19.     @Override  
  20.     public void updateCount() {  
  21.         System.out.println("修改账户方法...");  
  22.   
  23.     }  
  24.   
  25. }  
  26.   
  27. 、CountProxy.java  
  28. package net.battier.dao.impl;  
  29.   
  30. import net.battier.dao.Count;  
  31.   
  32. /** 
  33.  * 这是一个代理类(增强CountImpl实现类) 
  34.  *  
  35.  * @author Administrator 
  36.  *  
  37.  */  
  38. public class CountProxy implements Count {  
  39.     private CountImpl countImpl;  
  40.   
  41.     /** 
  42.      * 覆盖默认构造器 
  43.      *  
  44.      * @param countImpl 
  45.      */  
  46.     public CountProxy(CountImpl countImpl) {  
  47.         this.countImpl = countImpl;  
  48.     }  
  49.   
  50.     @Override  
  51.     public void queryCount() {  
  52.         System.out.println("事务处理之前");  
  53.         // 调用委托类的方法;  
  54.         countImpl.queryCount();  
  55.         System.out.println("事务处理之后");  
  56.     }  
  57.   
  58.     @Override  
  59.     public void updateCount() {  
  60.         System.out.println("事务处理之前");  
  61.         // 调用委托类的方法;  
  62.         countImpl.updateCount();  
  63.         System.out.println("事务处理之后");  
  64.   
  65.     }  
  66.   
  67. }  

 

3、TestCount.java 

    1. package net.battier.test;  
    2.   
    3. import net.battier.dao.impl.CountImpl;  
    4. import net.battier.dao.impl.CountProxy;  
    5.   
    6. /** 
    7.  *测试Count类 
    8.  *  
    9.  * @author Administrator 
    10.  *  
    11.  */  
    12. public class TestCount {  
    13.     public static void main(String[] args) {  
    14.         CountImpl countImpl = new CountImpl();  
    15.         CountProxy countProxy = new CountProxy(countImpl);  
    16.         countProxy.updateCount();  
    17.         countProxy.queryCount();  
    18.   
    19.     }  
    20. }  

由上面可以看出,静态代理的缺点是每个代理类只能为一个接口服务,这样一来程序开发中,必然会产生过多的代理,出现重复代码。解决这一问题最好的做法是可以通过一个代理类完成全部的代理功能,那么此时就必须使用动态代理完成。 

再来看动态代理:

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<?>[] interfaces, 
InvocationHandler h) 
                               throws IllegalArgumentException 
参数说明: 
ClassLoader loader:类加载器 
Class<?>[] interfaces:得到全部的接口 
InvocationHandler h:得到InvocationHandler接口的子类实例 

1.Person类

package cn.itcast.proxy;

public interface Person {

public abstract String sing(String name);

public abstract String dance(String name);

}

2.Liming类

package cn.itcast.proxy;

public class Liming implements Person {

@Override
public String sing(String name){
System.out.println("李明唱"+name+"歌了!!");
return "谢谢";
}


@Override
public String dance(String name){
System.out.println("李明跳"+name+"舞了!!");
return "飞吻";
}
}

3.动态代理类

package cn.itcast.proxy;

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

public class LimingProxy {
private Person liming=new Liming();

public Person createProxy(){
return (Person) Proxy.newProxyInstance(LimingProxy.class.getClassLoader(), liming.getClass().getInterfaces(), new InvocationHandler() {

@Override
/**
* proxy:把代理对象自身传递进来
* method:代表当前调用的方法
* args:调用方法的参数
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
String methosName=method.getName();
if(methosName.equals("sing")){
System.out.println("拿一万块来!!");
return method.invoke(liming,args);
}else if(methosName.equals("dance")){
System.out.println("拿两万块来!!");
return method.invoke(liming, args);
}else{
System.out.println("李明不支持该功能!!");
}
return null;
}
});
}
}

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

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

1、BookFacadeCglib.java 

  1. package net.battier.dao;  
  2.   
  3. public interface BookFacade {  
  4.     public void addBook();  
  5. }  

 

2、BookCadeImpl1.java 

  1. package net.battier.dao.impl;  
  2.   
  3. /** 
  4.  * 这个是没有实现接口的实现类 
  5.  *  
  6.  * @author student 
  7.  *  
  8.  */  
  9. public class BookFacadeImpl1 {  
  10.     public void addBook() {  
  11.         System.out.println("增加图书的普通方法...");  
  12.     }  
  13. }  


3、BookFacadeProxy.java 

  1. package net.battier.proxy;  
  2.   
  3. import java.lang.reflect.Method;  
  4.   
  5. import net.sf.cglib.proxy.Enhancer;  
  6. import net.sf.cglib.proxy.MethodInterceptor;  
  7. import net.sf.cglib.proxy.MethodProxy;  
  8.   
  9. /** 
  10.  * 使用cglib动态代理 
  11.  *  
  12.  * @author student 
  13.  *  
  14.  */  
  15. public class BookFacadeCglib implements MethodInterceptor {  
  16.     private Object target;  
  17.   
  18.     /** 
  19.      * 创建代理对象 
  20.      *  
  21.      * @param target 
  22.      * @return 
  23.      */  
  24.     public Object getInstance(Object target) {  
  25.         this.target = target;  
  26.         Enhancer enhancer = new Enhancer();  
  27.         enhancer.setSuperclass(this.target.getClass());  
  28.         // 回调方法  
  29.         enhancer.setCallback(this);  
  30.         // 创建代理对象  
  31.         return enhancer.create();  
  32.     }  
  33.   
  34.     @Override  
  35.     // 回调方法  
  36.     public Object intercept(Object obj, Method method, Object[] args,  
  37.             MethodProxy proxy) throws Throwable {  
  38.         System.out.println("事物开始");  
  39.         proxy.invokeSuper(obj, args);  
  40.         System.out.println("事物结束");  
  41.         return null;  
  42.   
  43.   
  44.     }  
  45.   
  46. }  


4、TestCglib.java 

    1. package net.battier.test;  
    2.   
    3. import net.battier.dao.impl.BookFacadeImpl1;  
    4. import net.battier.proxy.BookFacadeCglib;  
    5.   
    6. public class TestCglib {  
    7.       
    8.     public static void main(String[] args) {  
    9.         BookFacadeCglib cglib=new BookFacadeCglib();  
    10.         BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  
    11.         bookCglib.addBook();  
    12.     }  
    13. }  

 

以上是关于java动态代理的主要内容,如果未能解决你的问题,请参考以下文章

Java设计模式-代理模式之动态代理(附源代码分析)

Java设计模式---代理模式---动态代理

有关java的动态代理和代理模式

java 代理模式二:动态代理

Java动态代理设计模式

Java动态代理原理