目前最常用两种动态代理就是JDK和CGLIB,一种是JDK自带的,一种是三方技术。
两者区别:
JDK:JDK动态代理是java.lang.reflect.*包提供的方式,它必须借助一个接口才能产生代理对象。
CGLIB:在一些不能提供接口的环境中,只能采用其他第三方技术,比如CGLIB动态代理。它的优势在于不需要提供接口,只要一个非抽象类就能实现动态代理。
1.JDK代理
因为JDK需要接口才能产生代理对象,所以先创建一个接口
package service;
public interface HelloWordService {
void sayHello();
}
//实现类
package service.serviceimpl;
import service.HelloWordService;
public class HelloWordServiceImpl implements HelloWordService {
@Override
public void sayHello() {
System.out.println("Hello Word");
}
}
完成上面操作后,我们先要建立起代理对象和真实服务对象的关系,然后实现代理逻辑,所以一共分为两个步骤。
在 JDK 动态代理中,要实现代理逻辑类必须去实现 java.lang.reflect.InvocationHandler接口,它里面定义了一个invoke方法,并提供接口数组用于下挂代理对象,
package classtext;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxyExample implements InvocationHandler {
Object target=null;
//代理对象
public Object bind(Object target){
this.target=target;
/*newProxyInstance方法参数,第一个参数获得当前类加载器,第二个参数获得当前类接口
第三个参数代表当前对象并实现了InvocationHandler接口
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);
}
/*
* invoke代理方法参数
* 第一个参数是代理对象,第二个参数是当前调度方法,第三个参数是方法参数
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("进入代理逻辑模式");
System.out.println("在调度真实对象之前的服务");
Object obj=method.invoke(target,args);
System.out.println("在调度真实对象之后的服务");
return obj;
}
}
其中建立代理对象和真实对象的关系是通过下图实现的,实现代理逻辑的是ivnoke方法
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
单元测试如下图
public class ProxyTest {
public static void main(String[] args) {
//绑定关系,因为挂在接口HelloWord下,所以声明代理对象HelloWordService proxy
JDKProxyExample jdkProxyExample=new JDKProxyExample();
//此时proxy为代理对象,他会进入invoke方法里
HelloWordService proxy=(HelloWordService) jdkProxyExample.bind(new HelloWordServiceImpl());
proxy.sayHello();
输出结果:
进入代理逻辑模式
在调度真实对象之前的服务
Hello Word
在调度真实对象之后的服务
2.CGLIB
再不能提供接口时使用,只需要一个非抽象类即可实现动态代理
package service.serviceimpl;
public class ReflectServiceImpl {
public void sayHello(){
System.out.println("CGLIB代理");
}
}
动态代理逻辑类:
package classtext;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxyExample implements MethodInterceptor {
//创建代理对象
public Object getProxy(Class cls){
//增强类对象
Enhancer enhancer = new Enhancer();
//设置增强类型,通过setSuperclass设置它的代理类
enhancer.setSuperclass(cls);
//定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor
enhancer.setCallback(this);
//生成并返回代理对象
return enhancer.create();
}
/*
* 代理逻辑方法
* 第一个参数是代理对象 第二个参数是方法 第三个方法参数
* 第四个是调度方法
* */
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("调用真实对象之前");
//CGLIB反射调用真实对象
Object result=methodProxy.invokeSuper(proxy,args);
System.out.println("调用真实对象后");
return result;
}
}
单元测试:
CglibProxyExample cglibProxyExample=new CglibProxyExample();
ReflectServiceImpl reflectProxy=(ReflectServiceImpl) cglibProxyExample
.getProxy(ReflectServiceImpl.class);
reflectProxy.sayHello();
输出结果:
调用真实对象之前
CGLIB代理
调用真实对象后
两者十分相似,它们都是先获取代理对象之后调用代理逻辑实现,而代理逻辑要实现接口的一个方法,这个借口定义的方法就是代理逻辑的实现,它可以控制真实对象的方法。