本文已参与掘金创作者训练营第三期「话题写作」赛道,详情查看:掘力计划|创作者训练营第三期正在进行,「写」出个人影响力。
Spring的AOP动态代理有两种实现方式,JDK实现和CGLIB实现,那么两者有何种区别呢?
区别
JDK的动态代理主要是实现接口的方式,CGLIB主要是通过创建子类的方式,在父类的方法外进行操作。
- 如果类是接口的时候或者类是JDK创建的proxy类时使用的是JDK代理的
- 非接口类使用CGLib代理,或者配置注解中proxyTargetClass = true
两者的性能对比:
核心代码位置
JDK动态代理原理
JDK动态代理主要是通过,反射包中的Porxy类和InvokationHandler接口。它们结合在一起后可以创建动态代理类。Porxy类基于传递的参数创建动态代理类。InvokationHandler则用于激发动态代理类的方法。这个过程是在程序执行过程中动态生成与处理的,所以叫动态代理。
代码如下:
Porxy类
Porxy类提供了一个静态方法创建动态代理类。
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
复制代码
1、ClassLoader:ClassLoader会定义动态代理类,ClassLoader可以通过类或者接口获得,如果我们想通过接口获得,调用方法如下。
Task.class.getClassLoader()
复制代码
如果通过类来获得,加入我们有一个类TaskImpl实现了Task接口,我们有个TaskImpl的对象ob,然后ClassLoader获取方法如下
ob.getClassLoader()
复制代码
2、 Class<?>[] interfaces:动态代理类需要实现的接口
3、InvocationHandler:传递一个实现了InvokationHandler接口的类的实例
InvokationHandler
InvokationHandler是Java 反射包里面的一个接口。InvokationHandler通过用户类来实现,来激发一个动态代理类的方法。它只有一个方法:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
复制代码
1、Object:实现方法的代理对象 2、Method:代理实例激发的方法,Porxy参数中的接口方法 3、Object[]:传递给方法的一系列参数
实现
1、我们提供一个接口
package me.aihe;
public interface Task {
void setData(String data);
int getCalData(int x);
}
复制代码
2、实现这个接口
package me.aihe;
public class TaskImpl implements Task {
@Override
public void setData(String data) {
System.out.println(data+ " Data is saved");
}
@Override
public int getCalData(int x) {
return x * 10;
}
}
复制代码
3、定义自己的InvokationHandler类,并且实现InvokationHandler接口的Invoke方法
package me.aihe;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MyInvokationHandler implements InvocationHandler {
private Object obj;
public MyInvokationHandler(Object object){
this.obj = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
if(method.getName().contains("get")){
System.out.println("...get Method Executing...");
}else{
System.out.println("...set Method Executing...");
}
result = method.invoke(obj, args);
return result;
}
}
复制代码
4、创建一个工厂类获取动态代理类:
package me.aihe;
import java.lang.reflect.Proxy;
public class ProxyFactory {
public static Object newInstance(Object ob) {
return Proxy.newProxyInstance(ob.getClass().getClassLoader(),
new Class<?>[] { Task.class }, new MyInvokationHandler(ob));
}
}
复制代码
5、提供我们的测试类
package me.aihe;
public class Test {
public static void main(String[] args) {
Task task = (Task)ProxyFactory.newInstance(new TaskImpl());
task.setData("Test");
System.out.println("============");
System.out.println(task.getCalData(5));
}
}
复制代码
看到程序的输出结果:
...set Method Executing...
Test Data is saved
============
...get Method Executing...
50
复制代码
CGLIB代码案例
这里提供下使用方式。
1. 创建业务类
引入Maven:
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
复制代码
package cglib.enhancer;
public class Hello {
public String sayHello(boolean throwException) throws Exception {
System.out.println("hello everyone!");
if(throwException)
throw new Exception("test exception");
return "123";
}
}
复制代码
2. 实现MethodInterceptor接口
package cglib.enhancer;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class ProxyFactory implements MethodInterceptor {
//要代理的原始对象
private Object obj;
public Object createProxy(Object target) {
this.obj = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.obj.getClass());// 设置代理目标
enhancer.setCallback(this);// 设置回调
enhancer.setClassLoader(target.getClass().getClassLoader());
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
Object result = null;
try {
// 前置通知
before();
result = proxy.invokeSuper(obj, args);
// 后置通知
after();
} catch (Exception e) {
exception();
}finally{
beforeReturning();
}
return result;
}
private void before() {
System.out.println("before method invoke");
}
private void after() {
System.out.println("after method invoke");
}
private void exception() {
System.out.println("method invoke exception");
}
private void beforeReturning() {
System.out.println("before returning");
}
}
复制代码
3. 动态代理
package cglib.enhancer;
public class EnhancerTest {
public static void main(String[] args) throws Exception {
Hello hello = new Hello();
ProxyFactory cglibProxy = new ProxyFactory();
Hello proxy = (Hello) cglibProxy.createProxy(hello);
String result=proxy.sayHello(true);
System.out.println(result);
}
}
复制代码