使用JDK创建动态代理只能为接口创建代理实例,这第一点从Proxy的接口签名newProxyInstance(ClassLoader loader,Class[]interfaces,InvocationHandler h)中就可以看的很清楚:第二个入参interfaces就是需要代理实例的接口列表。对于没有接口定义的业务方法的类,则使用Cglib动态代理。
Cglib采用了非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势织入横切逻辑。
实例一:使用Cglib动态代理,对方法执行时间进行监控
Computer类
public class Computer {
public int add(int a,int b){
System.out.println("perform add method...");
try {
Thread.sleep(20);
}catch(InterruptedException e) {
e.printStackTrace();
}
return a+b;
}
public int plus(int a,int b){
System.out.println("perform plus method...");
try {
Thread.sleep(40);
}catch(InterruptedException e) {
e.printStackTrace();
}
return a-b;
}
}
监视器类
/**
* 用于记录性能监视信息
* method为目标类方法的全限定名
*/
public class MethodPerformance {
private long begin;
private long end;
private String serviceMethod;
public MethodPerformance(String serviceMethod){
this.serviceMethod=serviceMethod;
begin=System.currentTimeMillis();
}
public void printPerformance(){
end=System.currentTimeMillis();
long elapse=end-begin;
System.out.println(serviceMethod+" cost "+elapse+" ms");
}
}
/**
*性能监视器类
*/
public class PerformanceMonitor {
/*
* 通过一个ThreadLocal保存调用线程相关的性能监视信息,ThreadLocal是将非线程安全类改造为线程安全类的法宝
*/
private static ThreadLocal<MethodPerformance> performanceRecord=newThreadLocal<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();//打印方法性能监视结果
}
}
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(); //通过字节码技术动态创建子类实例
}
public Object intercept(Object obj, Method method, Object[] args,//拦截父类所有方法的调用
MethodProxy proxy) throwsThrowable {
PerformanceMonitor.begin(obj.getClass().getName()+"."+method.getName());
Object result=proxy.invokeSuper(obj, args); //通过代理类调用父类中的方法
PerformanceMonitor.end();
return result;
}
}
测试类:
public class Test {
public static void main(String[] args) {
CglibProxyproxy=new CglibProxy();
Computer c=(Computer)proxy.getProxy(Computer.class);
c.add(5,2);
c.plus(10,3);
}
}
输出结果:
begin monitor...
perform add method...
end monitor...
cglib1.Computer$$EnhancerByCGLIB$$5658ac9d.addcost 38 ms
begin monitor...
perform plus method...
end monitor...
cglib1.Computer$$EnhancerByCGLIB$$5658ac9d.pluscost 40 ms
在intercept(Object obj,Method method,Objects[] args,MethodProxy proxy)是CGLIB定义的Interceptor接口的方法,它拦截所有目标类方法的调用,obj标示目标类的实例,method为目标类方法的反射对象;args为方法的动态入参;而proxy为代理类的实例。
实例二:利用cglib动态代理,对增删改查方法进行权限过滤
BookBean实现了增删改查的业务功能
public class BookBean {
public void create(){
System.out.println("create is running");
}
public void delete(){
System.out.println("delete is running");
}
public void query(){
System.out.println("query is running");
}
public void update(){
System.out.println("update is running");
}
}
动态代理,实现业务逻辑横切面拦截(即权限过滤)
public class CglibProxy implementsMethodInterceptor {
private Logger log=Logger.getLogger(CglibProxy.class);
private String name;
private Enhancer enhancer=new Enhancer();
public CglibProxy(String name){
this.name=name;
}
public Object getBookBeanProxy(Class<?> clazz){
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
log.info("invoke method is "+method.getName());
if("zhangsan".equals(name)){
System.out.println("Permission denied! ");
return null;
}
Object result=proxy.invokeSuper(obj, args);
return result;
}
}
创建一个获取Bean工厂类
public class BookBeanFactory {
private static BookBean service=new BookBean();
public BookBeanFactory(){};
public static BookBean getInstance(){
return service;
}
/*
* 用于获取BookBean代理类而特别提供的方法,也可以忽略直接用上面通用的方法
*/
public static BookBean getBookBeanProxyInstance(CglibProxy proxy){
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(BookBean.class);
enhancer.setCallback(proxy);
return (BookBean)enhancer.create();
}
}
测试类:
public class Client {
public static void doMethod(BookBean bean){
bean.create();
bean.delete();
bean.query();
bean.update();
}
public static void main(String[] args) {
//BookBean bean=BookBeanFactory.getInstance();
CglibProxyproxy=new CglibProxy("zhangsan");
// BookBeanbean=(BookBean)proxy.getBookBeanProxy(BookBean.class);
BookBeanbean =BookBeanFactory.getBookBeanProxyInstance(proxy);
doMethod(bean);
}
}
无权限的结果:
Permission denied!
Permission denied!
Permission denied!
Permission denied!
有权限的结果:
create is running
delete is running
query is running
update is running
通过动态代理实现对方法权限的使用,如果不用动态代理的话,就需要在每个方法中判断某人是否具有使用自己的权限,这将是很麻烦的。