动态代理

JDK动态代理
 
  场景:将业务逻辑代码中的监视代码,移除,利用动态代理在将监视代码加上,如在写一些数据库操作代码时,在操作的前后加上一些信息,或直接写成日志。

JDK的动态代理主要涉及到java.lang.reflect包中的两个类:ProxyInvocationHandler。其中 InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一 起。
  
ProxyInvocationHandler实现类动态创建一个符合某一接口的代理实例。这样讲一定很抽象,我们马上着手动用ProxyInvocationHandler这两个魔法戒对上一节中的性能监视代码进行AOP式的改造。
   
首先,我们编写业务类接口ForumService

package service;

public interface ForumService {

    public void removeTopic(int topicId);

   

    public void removeForum(int forumId);

}



     再者,我们编写业务实现类,此业务类ForumServiceImpl 中删除性能监视的横切代码,使ForumServiceImpl只负责具体的业务逻辑,如所示:

package service;

 

public class ForumServiceImpl implements ForumService {

 

    public void removeTopic(int topicId) {

       //

       System.out.println("模拟删除Topic记录:" + topicId);

       try {

           Thread.currentThread().sleep(20);

       } catch (Exception e) {

           throw new RuntimeException(e);

       }

//

    }

    public void removeForum(int forumId) {

//

       System.out.println("模拟删除Forum记录:" + forumId);

       try {

           Thread.currentThread().sleep(40);

       } catch (Exception e) {

           throw new RuntimeException(e);

       }

//

    }

}

 

 在代码清单 5中的①和②处,原来的性能监视代码被移除了,我们只保留了真正的业务逻辑。

    从业务类中移除的横切代码当然还得找到一个寄居之所,InvocationHandler就是横切代码的家园乐土,我们将性能监视的代码安置在PerformaceHandler中,如所示:

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

public class PerformaceHandler implements InvocationHandler {

    private Object target;

 

    public PerformaceHandler(Object target) {// target为目标的业务类

       this.target = target;

    }

 

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

           throws Throwable {

       System.out.println("业务类开始" + target.getClass().getName() + "."

              + method.getName());

       Object obj = method.invoke(target, args);// ②通过反射方法调用目标业务类的业务方法

       System.out.println("业务类结束");

       return obj;

    }

}

 

粗体部分的代码为性能监视的横切代码,我们发现,横切代码只出现一次,而不是原来那样星洒各处。大家注意②处的method.invoke(),该语句通 过反射的机制调用目标对象的方法,这样InvocationHandlerinvoke(Object proxy, Method method, Object[] args)方法就将横切代码和目标业务类代码编织到一起了,所以我们可以将InvocationHandler看成是业务逻辑和横切逻辑的编织器。下面, 我们对这段代码做进一步的说明。

首先,我们实现InvocationHandler接口,该接口定义了一个 invoke(Object proxy, Method method, Object[] args)的方法,proxy是代理实例,一般不会用到;method是代理实例上的方法,通过它可以发起对目标类的反射调用;args是通过代理类传入 的方法参数,在反射调用时使用。
   
此外,我们在构造函数里通过target传入真实的目标对象,如①处所示,在接口方法invoke(Object proxy, Method method, Object[] args)里,将目标类实例传给method.invoke()方法,通过反射调用目标类方法,如②所示。
   

下面,我们通过Proxy结合PerformaceHandler创建ForumService接口的代理实例,如所示:

import java.lang.reflect.Proxy;

 

import service.ForumService;

import service.ForumServiceImpl;

 

public class TestForumService {

    public static void main(String[] args) {

       ForumService target = new ForumServiceImpl();// ①目标业务类

       // ② 将目标业务类和横切代码编织到一起

       PerformaceHandler handler = new PerformaceHandler(target);

       // ③为编织了目标业务类逻辑和性能监视横切逻辑的handler创建代理类

       ForumService proxy = (ForumService) Proxy.newProxyInstance(target

              .getClass().getClassLoader(),

              target.getClass().getInterfaces(), handler);

       // ④ 操作代理实例

       proxy.removeForum(10);

       proxy.removeTopic(1012);

    }

}


上面的代码完成了业务类代码和横切代码编织和接口代理实例生成的工作,其中在②处,我们将ForumService实例编织为一个包含性能监视逻辑的 PerformaceHandler实例,然后在③处,通过Proxy的静态方法newProxyInstance()为融合了业务类逻辑和性能监视逻辑 的handler创建一个ForumService接口的代理实例,该方法的第一个参数为类加载器,第二个参数为创建的代理实例所要实现的一组接口,第三个参数是整合了业务逻辑和横切逻辑的编织器对象handler。按照③处的设置方式,这个代理实例就实现了目标业务类的所有接口,也即ForumServiceImplForumService接口。这样,我们就可以按照调用ForumService接口的实例相同的方式调用代理实例,运行以上的代码,输出以下的信息:

业务类开始service.ForumServiceImpl.removeForum

模拟删除Forum记录:10

业务类结束

业务类开始service.ForumServiceImpl.removeTopic

模拟删除Topic记录:1012

业务类结束

 
 


 我们发现,程序的运行效果和直接在业务类中编写性能监视逻辑的效果一致,但是在这里,原来分散的横切逻辑代码已经被我们抽取到 PerformaceHandler中。当其它业务类(如UserServiceSystemService等)的业务方法也需要使用性能监视时,我们 只要按照以上的方式,分别为它们创建代理对象就可以了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值