在上面的测试动态代理类中,我们调用了Proxy类的newProxyInstance()方法来获取一个代理类示例。这个代理类实现了我们指定的接口,并且会把方法调用分发到指定的调用处理器。首先通过newProxyInstance()方法获取代理类的示例,之后就可以通过这个代理类的实例调用代理类的方法,对代理类的方法调用都会调用中间类(实现了InvocationHandler接口的类)的invoke()方法,在invoke()方法中我们调用委托类的对应方法,然后加上了自己的处理逻辑。
JDK动态代理最大的特点就是动态生成的代理���和委托类实现同一个接口。JDK动态代理其实内部是通过反射机制(Proxy.newProxyInstance)实现的,也就是已知的一个对象,在运行的时候动态调用它的方法,并且调用的时候还可以加一些自己的逻辑。
CGLIB动态代理
JDK动态代理依赖接口实现,而当我们只有类没有接口的时候,就需要使用另一种动态代理技术:CGLIB动态代理。首先CGLIB动态代理是第三方框架实现的,需要在Maven工程中引入cglib的包:
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2</version>
</dependency>
CGLIB代理是针对类来实现代理的,原理是对指定的委托类生成一个子类并重写其中的业务方法来实现代理。代理类对象是由Enhancer类创建的。CGLIB创建动态代理类的模式是:
1.查找目标类上的所有非final的public方法(final的方法不能被重写)。
2.将这些方法的定义转为字节码。
3.将字节码转换成相应的代理的Class对象,然后通过反射获得代理类的实例对象。
4.实现MethodInterceptor接口,用来处理对代理类上所有方法的请求。
定义一个简单类
// 委托类,是一个简单类
public class HelloClass {
public void sayHello(String userName){
System.out.println("hello, " + userName);
}
public void sayByeBye(String userName){
System.out.println("byebye, " + userName);
}
}
定义一个实现MethodInterceptor类的拦截类
// HelloInterceptor 用于对方法调用拦截以及回调
public class HelloInterceptor implements MethodInterceptor {
/**
* CGLIB 增强类对象,代理类对象是由 Enhancer 类创建的,
* Enhancer 是 CGLIB 的字节码增强器,可以很方便的对类进行拓展
*/
private Enhancer enhancer = new Enhancer();
/**
*
* @param obj 被代理的对象
* @param method 代理的方法
* @param args 方法的参数
* @param proxy CGLIB方法代理对象
* @return cglib生成用来代替Method对象的一个对象,使用MethodProxy比调用JDK自身的Method直接执行方法效率会有提升
*/
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("方法调用之前");
Object o = proxy.invokeSuper(obj, args);
System.out.println("方法调用之后");
return o;
}
/**
* 使用动态代理创建一个代理对象
* @param c 类名
*/
public Object newProxyInstance(Class<?> c) {
// 设置产生的代理对象的父类,增强类型
enhancer.setSuperclass(c);
// 定义代理逻辑对象为当前对象,要求当前对象实现 MethodInterceptor 接口
enhancer.setCallback(this);
// 使用默认无参数的构造函数创建目标对象,这是一个前提,被代理的类要提供无参构造方法
return enhancer.create();
}
}
通过拦截类访问委托类
// 测试类
public class HelloTest {
public static void main(String[] args) {
HelloInterceptor helloInterceptor = new HelloInterceptor();
HelloClass sayHelloClass = (HelloClass) helloInterceptor.newProxyInstance(HelloClass.class);
sayHelloClass.sayHello("yanggb");
sayHelloClass.sayByeBye("yanggb");
}
}