一:JDK动态代理
1,JDK动态代理类使用步骤
1,定义一个接口及其实现类;
2,自定义 InvocationHandler 并重写invoke方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)
并自定义一些处理逻辑;
3,通过 Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
方法创建代理对象;
2,创建接口及实现类
接口
public interface SendMessage {
String send();
}
实现类(目标类)
public class AliSendMessage implements SendMessage {
@Override
public void send() {
String str = "阿里代理发送验证码";
System.out.println(str);
}
}
3,创建代理类
public class SendMessageProxy implements InvocationHandler {
private Object target;
public SendMessageProxy(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 代理增强内容
System.out.println("代理增强");
// 目标类执行
method.invoke(target,args);
// 代理增强内容
System.out.println("代理增强");
return null;
}
}
4,JDK代理工厂(创建代理对象)
public class JdkProxyFactory {
/**
newProxyInstance方法的三个参数:
target.getClass().getClassLoader() – 定义代理类的类加载器
target.getClass().getInterfaces() - 目标类实现的接口列表
h – 使用的代理类对象
1,
*/
public static Object getProxy(Object target){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),new SendMessageProxy(target));
}
}
5,创建使用代理对象
public class ProxyTest {
public static void main(String[] args) {
SendMessage sendMessage =(SendMessage) JdkProxyFactory.getProxy(new AliSendMessage());
sendMessage.send();
}
}
6,结果
代理增强
阿里代理发送验证码
代理增强
二,CGLIB动态代理
1,CGLIB 动态代理类使用步骤
1,定义一个类(目标类);
2,自定义 MethodInterceptor 并重写 intercept 方法,intercept 用于拦截增强被代理类的方法,
和 JDK 动态代理中的 invoke 方法类似;
3,通过 Enhancer 类的 create()创建代理类;
2,定义一个目标类
public class SendMessage {
public void send() {
System.out.println("目标类的目标方法");
}
}
3,定义代理拦截器(拦截器可以约定需要增强的功能)
public class ProxyMethodInterceptor implements MethodInterceptor {
/**
* @param o 代理对象(目标对象)
* @param method 被拦截的方法(需要增强的方法)
* @param args 方法入参
* @param methodProxy 用于调用原始方法
*/
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("切面功能增强");
methodProxy.invokeSuper(o,args);
System.out.println("切面功能增强");
return null;
}
}
4,代理工厂(从中得到代理类)
public class ProxyFactory {
// 参数 Class<?> tClass是目标类的Class
public static Object getProxyClass(Class<?> tClass){
// 创建动态代理增强类
Enhancer enhancer = new Enhancer();
// 设置类加载器
enhancer.setClassLoader(tClass.getClassLoader());
// 设置被代理类(目标类)
enhancer.setSuperclass(tClass);
// 设置方法拦截器
enhancer.setCallback(new ProxyMethodInterceptor());
// 创建代理类
return enhancer.create();
}
}
5,测试
public class CglibProxyTest {
public static void main(String[] args) {
// 测试
SendMessage proxyClass = (SendMessage) ProxyFactory.getProxyClass(SendMessage.class);
proxyClass.send();
}
}
结果
切面功能增强
目标类的目标方法
切面功能增强
三,JDK 动态代理和 CGLIB 动态代理对比
JDK 动态代理只能代理实现了接口的类或者直接代理接口,而 CGLIB 可以代理未实现任何接口的类。
另外, CGLIB 动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此不能将被代理类声明为 final 类型的类和方法。
就二者的效率来说,大部分情况都是 JDK 动态代理更优秀, 随着 JDK 版本的升级,这个优势更加明显。