前言
本篇文章主要是起到过渡作用的。我们都知道springAOP的实现底层是靠JDK提供的接口动态代理和Cglib字节码增强技术来实现的,那么我们这篇文章主要就是说说到底如何使用编程的方式来用这俩个实现动态代理。
JDK的接口动态代理
直接看代码吧:
先定义一个Children接口:
package com.suxin.dynamicProxyAndCglib.jdk;
public interface Children {
void eat();
void sleep();
}
定义Alice,用来实现了Children接口
package com.suxin.dynamicProxyAndCglib.jdk;
//alice是一个小孩子
public class Alice implements Children{
//需要增强这个方法,在吃东西前需要先洗手,吃完东西需要刷牙
public void eat() {
System.out.println("吃东西");
}
public void sleep() {
System.out.println("睡觉了");
}
}
再定义一个ChildrenInvocationHandler,用来实现InvocationHandler接口
package com.suxin.dynamicProxyAndCglib.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ChildrenInvocationHandler implements InvocationHandler {
//实际对象
private Object children;
//构造方法
public ChildrenInvocationHandler(Object children) {
this.children = children;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//只对eat方法进行了增强
if(method.getName().equals("eat")) {
System.out.println("先洗手");
method.invoke(children,args);
System.out.println("吃完了,现在要刷牙");
}else {
//不是eat方法则还是原先的业务逻辑不做方法增强
method.invoke(children,args);
}
return null;
}
}
客户端main方法:
package com.suxin.dynamicProxyAndCglib.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Clinet {
public static void main(String[] args) {
Alice alice = new Alice();
//把目标对象存进去
InvocationHandler handler = new ChildrenInvocationHandler(alice);
//InvocationHandler的class对象,通过它来获取类加载器
Class clazz = handler.getClass();
ClassLoader classLoader = clazz.getClassLoader();
//获取alice实现的接口class对象的数组
Class[] interfaceClasses = alice.getClass().getInterfaces();
//创建实现了Children接口的代理对象
Children childrenProxy = (Children)Proxy.newProxyInstance(classLoader, interfaceClasses, handler);
childrenProxy.eat();//执行吃方法
childrenProxy.sleep();//执行睡觉方法
}
}
直接看控制台打印输出:
先洗手
吃东西
吃完了,现在要刷牙
睡觉了
可以看到通过JDK提供的InvocationHandler和Proxy类我们实现了动态代理。
优点:不依赖第三方jar包, 使用方便;随着JDK的升级,JDK动态代理的性能在稳步提升
缺点:只适用于实现了接口类;执行速度较慢
CGLib
CGLib(代码生成库)主要用于生成类代理。这是通过在运行时创建子类来实现的,其中方法调用被用户定义的方法拦截。另外,cglib提供了不同的扩展,例如bean实用程序。cglib构建于ASM之上
使用前
需要在项目中依赖cglib相关的jar包和asm jar包。因为SpringCore部分已经集成了cglib相关的源码了,所以我直接用的是spring框架。
上代码:
package com.suxin.dynamicProxyAndCglib.cglib;
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 CglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
/**
*获取代理对象
*/
public Object getProxy(Class clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
/**
*实现 MethodInterceptor接口方法
*/
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object result;
if(method.getName().equals("eat")) {
System.out.println("先洗手");
result = methodProxy.invokeSuper(object,args);
System.out.println("吃完了,现在要刷牙");
}else {
result = methodProxy.invokeSuper(object,args);
}
return result;
}
}
client的main方法进行运行
package com.suxin.dynamicProxyAndCglib.cglib;
import com.suxin.dynamicProxyAndCglib.jdk.Alice;
public class Client {
public static void main(String[] args) {
CglibProxy cglibProxy = new CglibProxy();
Alice alice = (Alice)cglibProxy.getProxy(Alice.class);
alice.eat();
alice.sleep();
}
}
给出控制台打印:
先洗手
吃东西
吃完了,现在要刷牙
睡觉了
优点:可以代理没有实现接口的对象;由于是动态生成字节码实现代理,因此代理对象的执行速度较快。
缺点:动态生成字节码虽然执行较快,但是生成速度很慢。
以上就是JDK动态代理和CGLib技术的使用demo,学习以后我们接下来就是学习Spring的AOP的源码了
网友评论