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 InvocationHandlerpublic 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 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"));
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的思想。
2.2.1 执行流程1)被代理类
package com.jpeony.spring.proxy.cglib;
public class HelloService {
public HelloService() {
System.out.println("HelloService构造");
}
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方法),所以执行速度比较快。
package com.jpeony.spring.proxy.cglib;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class MyMethodInterceptor implements MethodInterceptor{
@Override
public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("======插入前置通知======");
//invokeSuper是调用父类的方法(被代理类)
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("======插入后者通知======");
return object;
}
public Object getInstance(Class> clazz) throws Exception{
//利用ASM框架生成代理类
Enhance enhance = new Enhance();
//传入被代理类
enhance.setSuperclass(clazz);
enhance.setCallback(this);
return enhance.creat();
}
}
2.2.2 调用过程
1)代理类执行sayHello方法
2)调用方法拦截器的intercept(before–invokeSuper–after)
3)invokeSuper调用CGLIB$sayHello$0,该方法再调用被代理类的sayHello
invokeSuper通过调用被代理类的FastClass中的invoke方法来运行对应的方法的
CGlib通过继承被代理类生成代理类Class,此外还有另外两个文件,就是为代理类和被代理类生成的FastClass(不是和生成代理类时生成的,而是再第一次调用invoke或者invokeSuper时生成的缓存)。
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.3 两者对比
- JDK动态代理是实现了被代理对象的接口,CGlib是继承了被代理对象。
- 两者都在运行期间生成字节码,JDK方式直接写Class字节码文件,CGlib则是通过ASM框架来写Class,实现更复杂,生成代理类的效率低
- JDK方式是通过InvocationHandler中的invoke方法,而该方法再通过反射调用被代理类的方法;CGlib则通过FastClass机制来调用方法,故方法调用效率更高。
cglib生成代理类慢,方法执行速度略大于jdk,所以比较适合单例模式。spring默认使用jdk动态代理,如果类没有接口,则使用cglib。



