java 动态代理

来源:互联网 发布:蛐蛐钢琴软件 编辑:程序博客网 时间:2024/05/17 21:50

常用的两种代理机制是:一种是基于JDK的动态代理;另一种是基于CGlib的动态代理

  1.JDK 动态代理:

     JDK1.3之后,java提供了动态代理技术,允许开发者在运行期创建接口的代理实例。

    JDK的动态代理主要涉及到java.lang.reflect包的两个类Proxy和InvocationHandler,其中InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑 ,并通过反射机制调用目标类的代码,动态的将横切逻辑和业务逻辑编织在一起。而Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。

下面就通过具体的代码实例来说明JDK的动态代理的实现:

  性能监视在调用每一个目标方法时启动方法的性能监视,在目标方法调用完成时记录方法的花费时间。

public class ForumServiceImpl implements ForumService {

public void removeTopic(int topicId) {
         PerformanceMonitor.begin("com.proxy.ForumServiceImpl.removeTopic");//开始对该方法进行性能监视
System.out.println("模拟删除Topic记录:"+topicId);
try {
Thread.currentThread().sleep(20);
} catch (Exception e) {
throw new RuntimeException(e);
}
  PerformanceMonitor.end();//结束对该方法进行性能测试
}


public void removeForum(int forumId) {
  PerformanceMonitor.begin("com.proxy.ForumServiceImpl.removeForum");//开始对该方法进行性能监视
System.out.println("模拟删除Forum记录:"+forumId);
try {
Thread.currentThread().sleep(40);
} catch (Exception e) {
throw new RuntimeException(e);
}
          PerformanceMonitor.end();//结束对该方法进行性能测试
}
}

每个service类和每个业务方法体的前后都执行相同的代码逻辑,方法启动前调用PerformanceMonitor.begin()和方法执行结束后调用执行PerformanceMonitor.end()并给出性能监视结果。

PerformanceMonitor是一个性能监测的实现类:

public class PerformanceMonitor {
private static ThreadLocal<MethodPerformace> performaceRecord = new ThreadLocal<MethodPerformace>();
public static void begin(String method) {
System.out.println("begin monitor...");
MethodPerformace mp = performaceRecord.get();
if(mp == null){
mp = new MethodPerformace(method);
performaceRecord.set(mp);
}else{
   mp.reset(method);
}
}
public static void end() {
System.out.println("end monitor...");
MethodPerformace mp = performaceRecord.get();
mp.printPerformace();
}
}

MethodPerformace 用于记录性能监视信息的类:

public class MethodPerformace {
private long begin;
private long end;
private String serviceMethod;
    public MethodPerformace(String serviceMethod){
    reset(serviceMethod);
    }
    public void printPerformace(){
        end = System.currentTimeMillis();
        long elapse = end - begin;
        System.out.println(serviceMethod+"花费"+elapse+"毫秒。");
    }
    public void reset(String serviceMethod){
    this.serviceMethod = serviceMethod;
    this.begin = System.currentTimeMillis();
    }
}

显然,当某个方法需要性能监视时,就必须调整方法代码,在方法体前后增加性能监视和结束性能监视的代码。这些非业务逻辑的性能监视代码破坏了业务逻辑的纯粹性。这时就可以通过代理的方式,将业务类方法中开启和结束性能监视的横切代码从业务逻辑中完全移除。

  通过JDK动态代理实现:

  通过JDK实现动态代理需要两步:

  ①将性能监视横切代码放置到实现InvocationHandler 的类PerformaceHandler中

 public class PerformaceHandler implements InvocationHandler {


    private Object target;//目标业务类
public PerformaceHandler(Object target){
this.target = target;
}

       //实现接口类的方法

         proxy - 在其上调用方法的代理实例

         method - 对应于在代理实例上调用的接口方法的Method 实例。Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。

         args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为null。基本类型的参数被包装在适当基本包装器类(如java.lang.Integer 或            java.lang.Boolean)的实例中。 


public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
PerformanceMonitor.begin(target.getClass().getName()+"."+ method.getName());
Object obj = method.invoke(target, args);//通过反射调用目标业务的方法
PerformanceMonitor.end();
return obj;
}
}

②通过Proxy结合PerformaceHandler创建业务类的代理对象:

        ForumService target = new ForumServiceImpl();
  PerformaceHandler handler = new PerformaceHandler(target);
  ForumService proxy = (ForumService) Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(), handler);

代理对象生成后就可以通过调用代理对象的方法实现性能监测功能:

proxy.removeForum(1);
proxy.removeTopic(3);

使用JDK动态代理有一个限制,即它只能为接口创建代理实例,对于没用通过接口定义业务方法的类,JDK的代理技术显然已经黔驴技穷了,CGLib则能很好地实现这一点。

2.CGLib 代理技术:

   CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截技术拦截所有父类方法的调用,并在此时织入横切逻辑。下面我们就利用CGLib技术,编写一个可以为任何类创建织入性能监视的横切逻辑的代理对象的代理创建器。

public class CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();


public Object getProxy(Class clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/* obj-表示目标类的实例
* method-为目标类方法的反射对象
* args- 为方法的动态入参
* proxy-为代理类的实例
*/
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
PerformanceMonitor.begin(obj.getClass().getName()+"."+method.getName());
Object result=proxy.invokeSuper(obj, args);
PerformanceMonitor.end();
return result;
}
}

通过代理类的实例为业务类创建代理对象,并测试的代码如下:

//使用CGLib动态代理
CglibProxy proxy = new CglibProxy();
ForumService forumService = (ForumService)proxy.getProxy(ForumServiceImpl.class);
forumService.removeForum(10);
forumService.removeTopic(1023);

更多CGLib知识参见:http://blog.csdn.net/xiaohai0504/article/details/6832990

0 0
原创粉丝点击