Spring AOP基础—JDK动态代理
JDK动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。
首先写一个接口 ForumService.java 及其实现类 ForumServiceImpl.java ,主要包括二个方法,删除主题removeTopic 和 删除 removeForum。代码如下:
public class ForumServiceImpl implements ForumService { @SuppressWarnings("static-access") public void removeForum(int forumId) { System.out.println("模拟删除Forum记录:" + forumId); try { Thread.currentThread().sleep(20); } catch (InterruptedException e) { e.printStackTrace(); } } @SuppressWarnings("static-access") public void removeTopic(int topicId) { System.out.println("模拟删除Topic记录:" + topicId); try { Thread.currentThread().sleep(40); } catch (InterruptedException e) { e.printStackTrace(); } } }
现在需要对二个方法的执行效率进行监控,所以创建一个监控方法效率的类 PerformanceMonitor.java 和 一个辅助工具类 MethodPerformance.java。代码如下:
public class MethodPerformance { private long begin; private long end; private String serviceMethod; public MethodPerformance(String serviceMethod){ this.serviceMethod = serviceMethod; this.begin = System.currentTimeMillis(); } public void printPerformance(){ end = System.currentTimeMillis(); long elapse = end - begin; System.out.println(serviceMethod + "花费" + elapse + "毫秒"); } }
public class PerformanceMonitor { private static ThreadLocal<MethodPerformance> performanceRecord = new ThreadLocal<MethodPerformance>(); public static void begin(String method){ System.out.println("begin monitor……"); MethodPerformance mp = new MethodPerformance(method); performanceRecord.set(mp); } public static void end(){ System.out.println("end monitor……"); MethodPerformance mp = performanceRecord.get(); mp.printPerformance(); } }
为了将监控方法效率的代码织入到业务方法 removeTopic 和 removeForum中,我们创建代理类 PerformanceHandler.java,代码如下:
public class PerformanceHandler implements InvocationHandler { private Object target; public PerformanceHandler(Object target) { this.target = target; } 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; } }
首先,我们实现InvocationHandler接口,该接口定义了一个invoke(Object proxy,Method method,Object[] args)方法,proxy是最终生成的代理实例,一般不会用到;method是被代理目标实例的某个具体方法,通过它可以发起目标实例方法的反射调用;args是通过被代理实例某一个方法的入参,在方法 反射调用时使用。
此外,我们再构造函数里通过target传入希望被代理的目标对象,在InvocationHandler()接口方法invoke(Object proxy,Method method,Object[] args)里,将目标实例传给method.invoke()方法,调用目标实例的方法。
下面,我们通过Proxy结合PerformanceHandler创建ForumService接口的代理实例,这个代理实例实现了目标业务类的所有接口,即ForumServiceImpl的ForumService接口。这样我们就可以按照调用ForumService接口实例相同的方式调用代理实例。代码如下:
public class TestForumService { public static void main(String[] args) { ForumService target = new ForumServiceImpl(); PerformanceHandler handler = new PerformanceHandler(target); ForumService proxy = (ForumService) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler); proxy.removeForum(1001); proxy.removeForum(100); } }
执行结果如下:
begin monitor……
模拟删除Forum记录:1001
end monitor……
com.aop.ForumServiceImpl.removeForum花费16毫秒
begin monitor……
模拟删除Forum记录:100
end monitor……
com.aop.ForumServiceImpl.removeForum花费15毫秒