原始的性能监控功能中性能监控的代码和业务层代码混合在一起,当某个方法需要进行性能监控,就必须调整方法代码,在方法的前面后面加上性能监控代码,这些非业务逻辑的性能监控代码破坏了业务逻辑的纯粹性。
我们可以通过动态代理来实现两者分离,一种是jdk自带的动态代理,但是只能是创建接口的动态代理,还有一种是CGlib动态代理,可以创建实现类的代理
首先利用jdk实现动态代理,修改原来的代码
1、业务代码中删除性能监控代码,只留模拟删除的功能
package com.test.proxy;
/**
* @author Administrator
*
*/
public interface ForumService
{
void removeTopic(int topic);
void removeMessage(int messageId);
}
/**
*
*/
package com.test.proxy;
/**
*
* 业务类
* @author Administrator
*
*/
public class ForumServiceImpl implements ForumService
{
@SuppressWarnings("static-access")
public void removeTopic(int topic)
{
System.out.println("模拟删除topic记录"+topic);
try
{
Thread.currentThread().sleep(20);
}
catch(Exception e)
{
throw new RuntimeException(e);
}
}
@SuppressWarnings("static-access")
public void removeMessage(int messageId)
{
System.out.println("模拟删除messageId记录"+messageId);
try
{
Thread.currentThread().sleep(40);
}
catch(Exception e)
{
throw new RuntimeException(e);
}
}
}
2、新建一个自定义Handler
/**
*
*/
package com.test.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* @author Administrator
*
*/
public class PerformanceHandler implements InvocationHandler
{
//obj 为业务实例
private Object target;
public PerformanceHandler(Object target)
{
this.target = target;
}
@Override
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;
}
}
3、测试类
/**
*
*/
package com.test.proxy;
import java.lang.reflect.Proxy;
/**
* @author Administrator
*
*/
public class TestForumService
{
public static void main(String[] args) {
ForumService forumService = new ForumServiceImpl();//希望被代理的业务类
PerformanceHandler handler = new PerformanceHandler(forumService); //讲目标业务和横切代码(性能监控)编制在一起
ForumService proxy = (ForumService)Proxy.newProxyInstance(forumService.getClass().getClassLoader(),forumService.getClass().getInterfaces(),handler);
proxy.removeTopic(10);
proxy.removeMessage(20);
}
}
4、运行结果
begin monitor
模拟删除topic记录10
end monitor
com.test.proxy.ForumServiceImpl.removeTopic花费20毫秒.
begin monitor
模拟删除messageId记录20
end monitor
com.test.proxy.ForumServiceImpl.removeMessage花费40毫秒.
总结:
使用动态代理,就是建立一个编织器,例如此处的PerformanceHandler,将业务代码和性能监控的代码编织在一起了,而两边的代码都各自独立,相互不影响。
既然是代理,肯定知道用了反射的技术。
缺点:
1、目标业务类的所有方法都加了性能监控横切逻辑,有时候可能只需要对某些特定的方法实现横切逻辑
2、通过硬编码指定了织入横切逻辑的切入点,即在目标业务方法的开始前和开始后织入代码
3、在测试代码中,手工编写代理实例的创建,为不同类创建代理时,需要分别创建相应的Handler,无法通用