静态代理:
就是一种组合方式的,A类组合目标类,A类A方法中引用目标类的a方法;对其进行辅助实现;
若想调用目标类的a方法,直接可以用A类A方法代理执行;
1.动态代理:
JDK动态代理:就是字节码重组过程,主要是生成新的代理类并实现目标类全部方法;
因为是通过实现,被代理类都实现接口
JDK动态代理过程
1.首先通过getInstance获取目标类,然后通过反射获取其全部方法;
2.Proxy.newProxyInstance通过入参:类的classLoader, 类的接口方法,该JDKDemoPorxy;
来创建新的代理对象;并且实现全部接口方法;
Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
- 最终通过invoke 来调用方法;入参:新生成的代理类,调用的目标方法,方法入参 ;
作用对原有类的接口方法做业务增强,比如before(),after()等方法;
public Object invoke(Object proxy, Method method, Object[] args)
4.根据上述动态生成java代码,编译新生产的.class文件,重新加载到JVM运行
//具体使用例子
//jdk代理类
public class JDKMeipo implements InvocationHandler {
private Object target;
public Object getInstance(Object target) throws Exception {
this.target = target;
Class> clazz = target.getClass();
//反射获取目标类方法,并新生成一个代理类,并实现全部方法,其中invoke可以做逻辑切入
//入参类的classLoader,类的接口,该JDKDemoPorxy
return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
//入参:新生成的代理类,调用的目标方法,方法入参
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object obj = method.invoke(this.target, args);
after();
return obj;
}
private void before() throws Exception {
System.out.println("before+++");
}
private void after() {
System.out.println("after+++");
}
}
public interface Person {
void getName();
Long getCreateTime(String param);
}
//目标类
public class Customer implements Person {
@Override
public void getName() {
System.out.println("sally");
}
@Override
public Long getCreateTime(String param) {
System.out.println(param);
return System.currentTimeMillis();
}
}
//测试使用
public class JDKProxyTest {
public static void main(String[] args) throws Exception {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
Person student = (Person) new JDKMeipo().getInstance(new Customer());
student.getCreateTime();
// Person customer = (Person) new CglibProxyDemo().getInstance(Customer.class);
// customer.getName();
}
}
代理重组字节码反编译后生成的文件:
通过反编译新的代理类文件$Porxy;可以看到 他实现了所有方法,并在static静态块中用反射找到所有方法以m0,m1,m2....来命名方法
public final class $Proxy0 extends Proxy implements Person {
private static Method m1;
private static Method m3;
private static Method m4;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {省略}
public final void getName() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final Long getCreateTime() throws {
try {
return (Long)super.h.invoke(this, m4, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {省略}
public final int hashCode() throws { 省略}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.example.springbootdemo.model.Person").getMethod("getName");
m4 = Class.forName("com.example.springbootdemo.model.Person").getMethod("getCreateTime");
m2 = Class.forName("java.lang.Object").getMethod("toString");
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.CGlib动态代理
CGlib动态代理原理:是通过生成子类继承目标类,并覆盖;
CGlib动态代理过程
1.首先通过Enhancer,设置目标类,并设置代理为回调,生成代理类继承目标类;
public Object getInstance(Class> clazz) throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//生成代理类继承目标类
return enhancer.create();
}
2.当调用代理类中方法时,通过MethodInterceptor拦截或说回调到intercept,来触发MethodProxy.invokeSuper;
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
before();
//methodProxy invokeSuper触发并生FastClass类,通过FastClass机制
Object obj = methodProxy.invokeSuper(o,args);
after();
return obj;
}
若缓存中没有,其中为目标类和代理类各生成一个FastClass类,这类会为每个方法分配一个index;
FastClassInfo fci = fastClassInfo;
return fci.f2.invoke(fci.i2, obj, args);
获取当前代理类的FastClass类和index,当作入参就可以直接调用方法,省去反射调用;所以比JDK执行效率高;
FastClass不是和代理一起生成的,而是在第一次执行MethodProxy.invokeSuper生成的,并放在缓存中;
使用例子
public class CglibProxyDemo implements MethodInterceptor {
public Object getInstance(Class> clazz) throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//生成代理类继承目标类
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
before();
//methodProxy invokeSuper触发并生FastClass类,通过FastClass机制
Object obj = methodProxy.invokeSuper(o,args);
after();
return obj;
}
private void before() throws Exception {
System.out.println("before+++");
}
private void after() {
System.out.println("after+++");
}
}
public class CglibProxyTest {
public static void main(String[] args) throws Exception {
Person customer = (Person) new CglibProxyDemo().getInstance(Customer.class);
customer.getName();
}
}
代理类调用方法时,会MethodInterceptor拦截进入intercept,触发methodProxy.invokeSuper(o,args);
MethodProxy是很关键的,调用invokeSuper时,为目标类和代理类各生成一个FastClass类,这类会为每个方法分配一个index;
获取代理类的FastClass根据index,调用方法;
public class MethodProxy {
private Signature sig1;
private Signature sig2;
private CreateInfo createInfo;
private final Object initLock = new Object();
private volatile FastClassInfo fastClassInfo;
···
private void init() {
if (fastClassInfo == null) {
synchronized (initLock) {
if (fastClassInfo == null) {
CreateInfo ci = createInfo;
FastClassInfo fci = new FastClassInfo();
fci.f1 = helper(ci, ci.c1);
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(sig1);
fci.i2 = fci.f2.getIndex(sig2);
fastClassInfo = fci;
createInfo = null;
}
}
}
}
。。。
private static class FastClassInfo {
FastClass f1;
FastClass f2;
int i1;
int i2;
}
。。。。
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
//生成FastClass类 ,若有就从缓存中获取
init();
FastClassInfo fci = fastClassInfo;
//根据fci.i2的index,去调用方法
return fci.f2.invoke(fci.i2, obj, args);
}
catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
」