1 静态代理
1)接口
public interface person{
void eat();
}
2)被代理类
public class child implements person{
void eat(){
System.out.println("小孩吃饭");
}
}
3)代理类
public class proxyChild implements person{
private child c1;
public proxyChild (child c1){
this.c1 = c1;
}
void eat(){
before();
c1.eat();//child的eat函数
after();
}
void before(){
System.out.println("小孩吃饭前");
}
void after(){
System.out.println("小孩吃饭后");
}
}
缺点:每个代理类只能代理一个类。
2 动态代理
2.1 JDK实现
利用字节码重组技术,获取传入的被代理对象实现的接口interfaces,增强被代理对象功能的InvocationHandler,来动态生成新的代理类。
2.1.1 InvocationHandler
public class ProxyHandler implements InvocationHandler{
private Object object;
public ProxyHandler(Object object){
this.object = object;
}
@Override
//被代理类调用的函数最终会利用该函数来执行
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强逻辑
System.out.println("Before invoke " + method.getName());
//原始child的eat函数
method.invoke(object, args);
//增强逻辑
System.out.println("After invoke " + method.getName());
return null;
//可以根据method的名字来进行不同的增强逻辑
//if("eat".equals(method.getName())){
//System.out.println("增强1");
//Object invoke = method.invoke(obj, args);
//System.out.println("增强1");
//}else{
//System.out.println("增强2");
//Object invoke = method.invoke(obj, args);
//System.out.println("增强2");
//}
}
}
2.1.2 动态代理类
class DynamicProxy {
public static Object getInatance(Object obj) {
Class<?>[] interfaces = obj.getClass().getInterfaces();
Object o = Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new myInvocationHandler(obj));
//o就是返回的动态生成的代理类
return o;
}
}
2.1.3 调用
public class JDKProxy {
public static void main(String[] args) {
UserService userService = (UserService) DynamicProxy.getInatance(new UserServiceImpl());
userService.login(10);
//会调用ProxyHandler里面的invoke方法
userService.register(20);
}
}
2.1.4 原理
1)动态生成对象
Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new myInvocationHandler(obj));
根据传入的类加载器,被代理类的所有接口,增强功能的类;利用字节码重组生成动态代理类
2)Proxy0:动态代理类。 简单示例
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
final class $Proxy0 extends Proxy implements person{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);----------**传来的增强句柄**
}
===========================代理类的调用函数=============================
public final void eat() throws {
try {
super.h.invoke(this, m3, (Object[])null);
// super.h 就是传来的增强句柄
// 增强句柄中的invoke中加上了增强逻辑的child的eat函数
//由此可知,通过代理类来调用被代理类的函数,最终会调用InvocationHandler中的invoke函数来执行
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void walk() throws {
try {
super.h.invoke(this, m4, (Object[])null);
// super.h 就是传来的增强句柄
// 增强句柄中的invoke中加上了增强逻辑的child的eat函数
//由此可知,通过代理类来调用被代理类的函数,最终会调用InvocationHandler中的invoke函数来执行
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
=====================================================================
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("person").getMethod("eat", Class.forName("java.lang.String"));
m4 = Class.forName("person").getMethod("walk", Class.forName("java.lang.String"));
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
2.2 CGlib的动态代理
通过“继承”可以继承父类所有的公开方法,然后可以重写这些方法,在重写时对这些方法增强,这就是cglib的思想。
生成三个类:
第一个文件:代理类的FastClass类----->根据方法信息,快速找到代理类中的对应方法
第二个文件:代理类,继承自被代理类----->供外界调用
第三个文件:被代理类的FastClass类----->根据方法信息,快速找到被代理类中的对应方法,普通的invoke方法需要意义进行匹配查找
2.2.1 执行流程
1)被代理类
package com.jpeony.spring.proxy.cglib;
public class HelloService {
public HelloService() {
System.out.println("HelloService构造");
}
/**
* 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
*/
final public String sayOthers(String name) {
System.out.println("HelloService:sayOthers>>"+name);
return null;
}
public void sayHello() {
System.out.println("HelloService:sayHello");
}
}
2)方法拦截器:MethodInterceptor,代理类执行方法会执行这个方法,类似JDK中的InvocationHandler.
不同的是JDK中的invoke利用反射机制调用被代理类的方法,而CGlib则是利用代理类继承的被代理类的方法来调用的(其中还利用fastClass机制,为每个方法分一个index,将index作为入参执行fastClass中的invoke方法),所以执行速度比较快。
在调用目标方法时,CGLib会回调MethodInterceptor接口方法拦截,来实现你自己的代理逻辑,类似于JDK中的InvocationHandler接口。
package com.jpeony.spring.proxy.cglib;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* 自定义MethodInterceptor
*/
public class MyMethodInterceptor implements MethodInterceptor{
/**
* sub:cglib生成的代理对象
* method:被代理对象方法
* objects:方法入参
* methodProxy: 代理方法
*/
@Override
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("======插入前置通知======");
//invokeSuper是调用父类的方法(被代理类)
//在调用invokeSuper后,cglib内部会通过代理类的FastClass找到要执行的方法
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("======插入后者通知======");
return object;
}
}
动态代理类
public class CglibProxyFactory {
public static Object getProxy(Class<?> clazz) {
// 创建动态代理增强类
Enhancer enhancer = new Enhancer();
// 设置类加载器
enhancer.setClassLoader(clazz.getClassLoader());
// 设置被代理类
enhancer.setSuperclass(clazz);
// 设置方法拦截器
enhancer.setCallback(new DebugMethodInterceptor());
// 创建代理类
return enhancer.create();
}
}
HelloService helloService = (HelloService )CglibProxyFactory.getProxy(HelloService .class);
helloService.sayHello("java");
2.2.2 调用过程
1)代理类执行sayHello方法
2)调用方法拦截器的intercept(before–invokeSuper–after)
3)invokeSuper调用CGLIB$sayHello$0(代理类中的同名方法),该方法再调用被代理类的sayHello
invokeSuper通过调用被代理类的FastClass中的invoke方法来运行对应的方法的
2.2.3 fastClass机制
CGlib通过继承被代理类生成代理类Class,此外还有另外两个文件,就是为代理类和被代理类生成的FastClass(不是和生成代理类时生成的,而是再第一次调用invoke或者invokeSuper时生成的缓存)。
普通jdk反射需要根据方法名和参数去查找相应的方法并执行,而falstClass有缓存,可以直接执行 object.targetFun();
1)被代理类的FastClass部分代码如下
public class HelloService$$FastClassByCGLIB$$8656ab6f extends FastClass {
public HelloService$$FastClassByCGLIB$$8656ab6f(Class var1) {
super(var1);
}
=====================================================================
//getIndex方法会为代理类和被代理类的方法分类index,这样每个index会对应到具体方法,在调用时就可以快速找到对应方法
public int getIndex(Signature var1) {
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -1488716497:
if (var10000.equals("sayOthers(Ljava/lang/String;)Ljava/lang/String;")) {
return 1;
}
break;
}
return -1;
}
=====================================================================
//invokeSuper那里,实际上就是用fastClass对象调用的invoke方法,查找是case n,运行相应的方法
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
HelloService var10000 = (HelloService)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
=====================================================================
var10000.sayHello();
=====================================================================
return null;
case 1:
return var10000.sayOthers((String)var3[0]);
case 2:
return new Boolean(var10000.equals(var3[0]));
case 3:
return var10000.toString();
case 4:
return new Integer(var10000.hashCode());
}
} catch (Throwable var4) {
throw new InvocationTargetException(var4);
}
}
}
2.2.4 代理类
public class Dog$$EnhancerByCGLIB$$4e9e4388 extends Dog implements Factory {
...............................
..............................
..............................
final String CGLIB$call$0() {
return super.call();
}
public final String call() {
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (this.CGLIB$CALLBACK_0 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
return var10000 != null ? (String)var10000.intercept(this, CGLIB$call$0$Method, CGLIB$emptyArgs, CGLIB$call$0$Proxy) : super.call();
}
..............................
..............................
..............................
}
2.3 两者对比
- JDK动态代理是实现了被代理对象的接口,CGlib是继承了被代理对象。
- 两者都在运行期间生成字节码,JDK方式直接写Class字节码文件,CGlib则是通过ASM框架来写Class,实现更复杂,生成代理类的效率低
- JDK方式是通过InvocationHandler中的invoke方法,而该方法再通过反射调用被代理类的方法;CGlib则通过FastClass机制来调用方法,故方法调用效率更高。
cglib生成代理类慢,方法执行速度略大于jdk,所以比较适合单例模式。spring默认使用jdk动态代理,如果类没有接口,则使用cglib。