静态代理:
代理前,所有东西都已知
动态代理:
在代理之前,都是未知的
package jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKmeipo implements InvocationHandler {
private Person xiaoluo;
public Object getInstance(Person xiaoluo){
this.xiaoluo=xiaoluo;
Class<?> clazz=xiaoluo.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this::invoke);
}
//method就是测试时,调用方法的反射对象;
// 1拿到被代理类对象的引用,并获取到所有接口,通过反射获取,method就是测试时,调用方法的反射对象;
// 2JDK的Proxy通过newProxyInstance自动生成一个新类,该类实现被代理类所有方法
// 3动态生成JAVA代码,把新加的业务逻辑通过一定的方式去调用
// Xiaoluo obj=(Xiaoluo) new Cglib58().getInstance(Xiaoluo.class);
// obj.findLove();
// 4编译新生成的JAVA代码.class
// 5再重新加载到JVM中
// 上述过程叫字节码重组
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("==========");
method.invoke(this.xiaoluo,args);
System.out.println("==========");
return null;
}
}
自动生成的新类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import jdk.Person;
public final class $Proxy0 extends Proxy implements Person {
private static Method m1;
private static Method m4;
private static Method m2;
private static Method m3;
private static Method m5;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
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 void findLove() throws {
try {
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 {
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 void buyHouse() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final void findJob() throws {
try {
super.h.invoke(this, m5, (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"));
m4 = Class.forName("jdk.Person").getMethod("findLove");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("jdk.Person").getMethod("buyHouse");
m5 = Class.forName("jdk.Person").getMethod("findJob");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
newInstance、invoke参数详解
method就是测试时,调用方法的反射对象;
https://www.cnblogs.com/fengmingyue/p/6092151.html
JDK中动态代理,只能代理一个接口 InvocationHandler(cglib代理对象灵活,若代理接口,则使用代理其实现类的方式实现),否者报错开头的,通常是自动生成的
CGLIB
CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
调用过程:代理对象调用this.setPerson方法->调用拦截器->methodProxy.invokeSuper->CGLIB$setPerson$0->被代理对象setPerson方法
cglib代理中需要的包
asm,cglib
asm框架解析
https://www.cnblogs.com/clds/p/4985893.html
代理模式作用:
AOP实现,拦截器,自己不想做但又不得不做的事的增强
**代理:**静态、动态;代理角色、被代理的角色(目标对象)
性能比较
CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,Cglib动态代理执行代理方法效率之所以比JDK的高是因为Cglib采用了FastClass机制,它的原理简单来说就是:为代理类和被代理类各生成一个Class,这个Class会为代理类或被代理类的方法分配一个index(这里的返回值,通过该返回值,查找对应的方法,即通过一个int参数,找到方法进行,最终在methodProxy.invokeSuper()执行方法
public int getIndex(Signature var1){
String var10000 = var1.toString();
switch(var10000.hashCode()) {
case -2071771415:
if (var10000.equals("CGLIB$clone$6()Ljava/lang/Object;")) {
return 23;
}
break;
case -2055565910:
if (var10000.equals("CGLIB$SET_THREAD_CALLBACKS([Lnet/sf/cglib/proxy/Callback;)V")) {
return 12;
}
break;
return -1;
}
)。这个index当做一个入参,FastClass就可以直接定位要调用的方法直接进行调用,这样省去了反射调用,所以调用效率比JDK动态代理通过反射调用高。
参考:https://blog.csdn.net/weixin_33883178/article/details/92375100
但是CGLib在创建代理对象时所花费的时间却比JDK多得多(JDK和Cglib都是在运行期生成字节码,JDK是直接写Class字节码,Cglib(适用於单例模式)使用ASM框架写Class字节码,Cglib代理实现更复杂,生成代理类比JDK效率低。),所以对於单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。
FastClass并不是跟代理类一块生成的,而是在第一次执行MethodProxy invoke/invokeSuper时生成的并放在了缓存中。
如下可获得反编译获得生成的类
package cglib;
import jdk.Person;
import net.sf.cglib.core.DebuggingClassWriter;
import sun.misc.ProxyGenerator;
import java.io.FileOutputStream;
public class CglibProxyTest {
public static void main(String[] args) {
try {
//只能实现接口的实现类
//获得生成类 System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:\\IDEAWorkSpace\\proxy\\src\\$Cglib0.class");
Mingjie obj=(Mingjie) new Cglib58().getInstance(Mingjie.class);
obj.findLove();
}catch (Exception e){
e.printStackTrace();
}
//
}
}
总结
1.JDK动态代理是实现了被代理对象的接口,Cglib是继承了被代理对象。
2.JDK和Cglib都是在运行期生成字节码,JDK是直接写Class字节码,Cglib(适用於单例模式)使用ASM框架写Class字节码,Cglib代理实现更复杂,生成代理类比JDK效率低。
3.JDK调用代理方法,是通过反射机制调用,Cglib是通过FastClass机制直接调用方法,Cglib执行效率更高。
Cglib执行流程:
通过Hnhancer创建新生成的代理类(asm框架字节码创建类)->
代理类继承被代理类方法,当测试类中调用
Mingjie obj=(Mingjie) new Cglib58().getInstance(Mingjie.class);
obj.findLove();
类似下面的方法时,实际上调用的是新生成的代理类中的方法(即被代理类的子类的方法),子类方法中对应的findlove()内部,通过创建一个MethodIntercept对象,来调用intercept(…)方法->
这时intercept(…)中的methodProxy.invokeSuper(…)会被执行
public Object invokeSuper(Object obj, Object[] args) throws Throwable {
try {
this.init();
MethodProxy.FastClassInfo fci = this.fastClassInfo;
//FastClass中有一个getIndex方法,参数是代理类和被代理类的signature签名,会返回一个int值,通过int值,FastClass中的invoke方法,可以找到对应代理类方法
return fci.f2.invoke(fci.i2, obj, args);
} catch (InvocationTargetException var4) {
throw var4.getTargetException();
}
}
private static class FastClassInfo {
FastClass f1;//被代理类FastClass
FastClass f2;//代理类FastClass
int i1; //被代理类的方法签名(index)
int i2;//代理类的方法签名
private FastClassInfo() {
}
}
//MethodProxy invoke/invokeSuper都调用了init()
private void init() {
if(this.fastClassInfo == null) {
Object var1 = this.initLock;
synchronized(this.initLock) {
if(this.fastClassInfo == null) {
MethodProxy.CreateInfo ci = this.createInfo;
MethodProxy.FastClassInfo fci = new MethodProxy.FastClassInfo();
fci.f1 = helper(ci, ci.c1);//如果缓存中就取出,没有就生成新的FastClass
fci.f2 = helper(ci, ci.c2);
fci.i1 = fci.f1.getIndex(this.sig1);//获取方法的index
fci.i2 = fci.f2.getIndex(this.sig2);
this.fastClassInfo = fci;
this.createInfo = null;
}
}
}
}
,且同时生成两个FastClass,与新生成的代理类和被代理类对应,FastClass中有一个getIndex方法,参数是代理类和被代理类的signature签名,会返回一个int值,通过int值,得到对应的新生成的代理类方法。这时候,被代理类的方法就会被执行了。
策略模式
举例
购物付款流程图
目录结构
创建订单类:
Order.java
import pay.PayState;
import pay.PayType;
import pay.Payment;
public class Order {
private String uid;
private String orderId;
private double amount;
public Order(String uid,String orderId,double amount){
this.amount=amount;
this.orderId=orderId;
this.uid=uid;
}
public PayState pay(PayType payType){
return payType.get().pay(this.uid,this.amount);
}
}
数据持久类
Paystate.java
package pay;
public class PayState {
private int code;
private Object data;
private String msg;
public PayState(int code, Object data, String msg){
this.code=code;
this.data=data;
this.msg=msg;
}
@Override
public String toString() {
return ("支付状态{" +
code +"}," +
msg +
", 交易详情" + data);
}
}
定义接口
Payment.java
package pay;
public interface Payment {
public PayState pay(String uid, double amount);
}
实现接口
JdPay.java
package pay;
public class Jdpay implements Payment{
@Override
public PayState pay(String uid, double amount) {
System.out.println("京
东,开始扣款");
return new PayState(200,amount,"支付成功");
}
}
枚举类:让每一种支付方式可一直使用
Paytype.java
package pay;
public enum PayType {
Ali_Pay(new AliPay()),Jd_Pay(new Jdpay());
private Payment payment;
PayType(Payment payment){
this.payment=payment;
}
public Payment get(){
return this.payment;
}
}
测试类
import pay.Jdpay;
import pay.PayType;
public class Paytest {
public static void main(String[] args) {
Order order=new Order("1","1111111",333.3);
System.out.println(order.pay(PayType.Ali_Pay));
}
}
现在直接使用各支付方式支付,使用时,只需要在枚举类中添加,代码更健壮,更易修改、维护