Java的动态代理

 为什么JDK代理只能对接口实现代理?

1、动态代理的几种方式 

 Java主要有两种代理,JDK和Cglib动态代理。先看JDK代理实例如下:

JDK动态代理的原理是根据定义好的规则,用传入的接口创建一个新类,这就是为什么采用动态代理时为什么只能用接口引用指向代理,而不能用传入的类引用执行动态类。

JDK创建代理有一个限制,即它只能为接口创建代理实例。举个例子如下:

public interface Advice {
	void beforeMethod();
	void afterMethod();
}

public class TimeAdvice implements Advice {
	long startTime;
	long endTime;

	public void beforeMethod() {
		startTime = System.nanoTime(); // 获取开始时间
		System.out.println("开始计算程序运行时间" + startTime);
	}

	public void afterMethod() {
		endTime = System.nanoTime(); // 获取结束时间
		System.out.println("计算程序运行时间: " + (endTime - startTime) + "ns");
	}
}
public interface SalaryInterface {  
    public void doSalary();  
}
public class Salary  implements SalaryInterface{  
    public void doSalary() {  
          System.out.println("进行薪资计算的逻辑处理");  
      }  
}

  

import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
import java.lang.reflect.Proxy;  
/* 
 * 每一个代理实例都必须指定一个调用处理器,代理对象调用方法时, 
 * 该方法会指派到调用处理器的invoke()中去。代理的方法封装成 
 * invoke中的method对象,其中的参数封装成Object[]. 
 */  
public class MyProxy implements InvocationHandler{  
	
     private Object obj;   // 希望被代理的对象  
     private Advice advice;  
     
    // 绑定代理对象  
    public Object bind(Object obj, Advice advice) {  
        this.obj = obj;  
        this.advice = advice;  
        return Proxy.newProxyInstance(  
                obj.getClass().getClassLoader(), // 类加载器    
                obj.getClass().getInterfaces(),  // 创建目标类所需要使用的一组接口  
                this  // 一个实现InvocationHandler的实例,用来整合横切与业务逻辑  
            );  
        }  
  
    /* 
     * 实现代理
     * method为方法名,args为代理实例某一方法的入参数组,而obj为所属的实例对象 
     */  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
        Object result = null;  
        try {  
            advice.beforeMethod();  
            result = method.invoke(obj, args);   
            advice.afterMethod();  
        } catch (Exception e){  
            e.printStackTrace();  
        }  
        return result;  
    }  
}  
public class Bootstrap {

	public static void main(String[] args) {
		
        Advice advice = new TimeAdvice();   
        SalaryInterface p = new Salary();  
        // Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象  
        MyProxy proxy = new MyProxy();  
          
        SalaryInterface y = (SalaryInterface)proxy.bind(p, advice);  
        y.doSalary(); // 相当于调用proxy.invoke(proxy, "doSalary, null);  
	}
}
开始计算程序运行时间43041762316001
进行薪资计算的逻辑处理
计算程序运行时间: 882610ns

  

CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,并顺势织入横切逻辑。  

CGGlib创建的代理对象要比JDK的性能高很多,但是创建时所花费的时间却比JDK动态代理要多。所以对于singleton的代理对象或者具有实例池的代码,由于无须频繁创建代码对象,用CGLib比较合适。也就是生命周期长的实例用CGLib比较合适。并且无法对final方法进行代理

/** 
 * 使用cglib动态代理 
 */  
public class Cglib implements MethodInterceptor {  
    private Object target;  
    long startTime;
   	long endTime;
  
    /** 
     * 创建代理对象 
     */  
    public Object getInstance(Object target) {  
        this.target = target;  
        Enhancer enhancer = new Enhancer();  
        enhancer.setSuperclass(this.target.getClass());  // 设置需要创建子类的类 
        enhancer.setCallback(this);   // 回调方法   
        return enhancer.create();     // 通过字节码技术动态创建子类实例   
    }  
  
    @Override  
    // 回调方法 ,拦截所有的父类方法调用 
    public Object intercept(Object obj, Method method, Object[] args,MethodProxy proxy) throws Throwable {  
    	startTime = System.nanoTime(); // 获取开始时间
		System.out.println("开始计算程序运行时间" + startTime);
        Object result = proxy.invokeSuper(obj, args);   // 通过代码类调用父类中的方法
        endTime = System.nanoTime();   // 获取结束时间
		System.out.println("计算程序运行时间: " + (endTime - startTime) + "ns");
        return result;  
    }  
   
}  

  

/*
 * 采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截的技术拦截
 * 所有父类方法的调用,并顺势织入横切逻辑
 * 
 * singletom的代理对象或者具有实例池的代理,因为无须频繁创建代理对象,比较适合用CGLib动态代理技术
 * 
 * 由于CGLib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final,private等方法进行代理
 */
public class TestCglib {
	   
    public static void main(String[] args) {  
        Cglib cglib=new Cglib();  
        Salary salary=(Salary)cglib.getInstance(new Salary());  
        salary.doSalary();  
    }  
}
原文地址:https://www.cnblogs.com/mazhimazhi/p/9633014.html