实现动态代理有两种方式:JDK动态代理和CGLIB动态代理。JDK动态代理需要提供接口,MyBatis的Mapper的实现方式就是,CGLIB不需要提供接口,延迟加载就是其应用。
第一种:JDK动态代理的演示。
- 编写服务类和接口,是真正的服务提供者;
- 编写代理类,提供绑定和代理方法。
服务接口
public interface HelloSerevice {
public void sayHello(String name);
}
接口的实现类
public class HelloServiceImpl implements HelloSerevice{
@Override
public void sayHello(String name) {
System.out.println("您好"+name);
}
}
代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//代理类,提供真实对象的绑定和代理方法,代理类的要求是实现InvocationHandler接口的代理方法
public class HelloServiceProxy implements InvocationHandler{
private Object target;
//绑定真实提供服务的对象
public Object bind(Object target) {
this.target = target;
/**
* 获得代理对象
* 第一个参数:获得类加载器
* 第二个参数:代理对象所属的接口
* 第三个对象:this表示当前类,提供服务的代理类
*/
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this);//jdk代理需要提供接口
}
@Override
/**Object proxy代理对象
* Method method提供的方法
* Object[] args方法的参数
*/
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
System.out.println("-----------我是jdk动态代理----------");
System.out.println("方法调用前...");
//通过反射调用真正提供服务的对象方法
result = method.invoke(target, args);
System.out.println("方法调用后...");
return result;
}
}
测试类
//测试类
public class HelloServiceTest {
public static void main(String[] args) {
HelloServiceProxy hsp = new HelloServiceProxy();
HelloServices hs = (HelloServices)hsp.bind(new HelloServiceImpl());
hs.sayHello("后羿");
}
}
输出:
-----------我是jdk动态代理----------
方法调用前...
您好啊!后羿
方法调用后...
MyBatis在实现Mapper接口就是这么做的。
第二种:CGLIB动态代理
JDK动态代理有一个缺点就是必须提供接口才可以使用,所以有了CGLIB动态代理,是一款流行的动态代理开源框架。
接口和实现类都不需要改变,下面实现CGLIB代理类,注意MethodInterceptor我是在Springboot项目中实现的,Java基础包中没有这个接口。
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
public class HelloServiceCgLib implements MethodInterceptor{
private Object target;
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 {
Object result = null;
System.out.println("我是CGLIB动态代理");
System.out.println("代理方法调用前...");
result = proxy.invokeSuper(obj, args);
System.out.println("代理方法调用后...");
return result;
}
}
测试类
//测试类
public class HelloServiceCGLibTest {
public static void main(String[] args) {
HelloServiceCgLib hscl = new HelloServiceCgLib();
HelloServiceImpl hsl = (HelloServiceImpl)hscl.getInstance(new HelloServiceImpl());
hsl.sayHello("伽罗");
}
}
输出:
我是CGLIB动态代理
代理方法调用前...
您好啊!伽罗
代理方法调用后...
通常在MyBatis的延迟加载在会用到CGLIB动态代理。