特点:被代理对象和代理对象必须实现同一个接口(比较好理解)–直接上代码示例如下:
//被代理类和代理类必须实现的接口
public interface BuyHouse {
/**
* 买房操作接口
* @param name 买房者
*/
void buyHouse(String name);
}
被代理类:
public class BuyHouseImpl implements BuyHouse {
@Override
public void buyHouse(String name) {
System.out.println(name+"在 "+LocalDate.now().toString() +" 买房了");
}
}
代理类:
public class StaticBuyHouseProxy implements BuyHouse {
private BuyHouse buyHouse;
public StaticBuyHouseProxy(final BuyHouse buyHouse) {
this.buyHouse = buyHouse;
}
@Override
public void buyHouse(String name) {
System.out.println("买房前咨询中介看房~~~~");
buyHouse.buyHouse(name);
System.out.println("买房后咨询装修公司装修~~~~~");
}
}
测试示例代码:
public static void main(String[] args) {
BuyHouse buyHouse = new BuyHouseImpl();
StaticBuyHouseProxy staticBuyHouseProxy = new StaticBuyHouseProxy(buyHouse);
staticBuyHouseProxy.buyHouse("李四");
}
总结:静态代理更类似于装饰者模式,利用被代理者对象的注入执行真正的业务操作,只是在执行业务前后进行一些其他业务处理
特点:被代理对象必须实现接口,但是不需要创建实现接口的代理类,由运行程序时动态生成代理对象
缺点:还是被接口限制,无法为普通的类进行代理
示例代码如下:
接口:
//被代理对象必须实现的接口
public interface BuyHouse {
/**
* 买房操作
* @param name 买房者
*/
void buyHouse(String name);
}
被代理类:
public class BuyHouseImpl implements BuyHouse {
@Override
public void buyHouse(String name) {
System.out.println(name+"在 "+LocalDate.now().toString() +" 买房了");
}
}
执行代理操作的handler处理器:
public class BuyHouseProxyHandler implements InvocationHandler {
private Object object;
public BuyHouseProxyHandler(final Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("JDK动态:"+args[0]+"代理买房前找中介咨询~~");
Object invoke = method.invoke(object, args);
System.out.println("JDK动态:"+args[0]+"代理买房后找装修公司咨询~~~");
return invoke;
}
}
测试代码:
public static void main(String[] args) {
BuyHouse buyHouse = new BuyHouseImpl();
//生成代理对象
BuyHouse house =(BuyHouse) Proxy.newProxyInstance(BuyHouse.class.getClassLoader(), buyHouse.getClass().getInterfaces(), new BuyHouseProxyHandler(buyHouse));
house.buyHouse("张三");
}
特点:被代理对象不需要实现接口,脱离了接口限制,CGLIB 创建代理对象的时间比JDK代理创建对象时间长得多,但是代理对象的性能比JDK动态代理创建的代理对象要高的多
示例代码如下:
被代理类:
public class BuyCar {
public void buyCar(String name){
System.out.println(name+"买车了~~~");
}
}
代理操作的方法拦截器:
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGLIBProxyBuyCar implements MethodInterceptor {
private Object target;
public CGLIBProxyBuyCar(final Object target) {
this.target = target;
}
//获取代理对象
public Object getProxyInstance(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
//执行被代理对象的方法时的拦截方法
//Object 参数为代理对象,此处有坑
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println(args[0]+"买车前试驾~~~");
//Object result = methodProxy.invoke(this.target, args);
//Object result = methodProxy.invokeSuper(o, args);
Object result = method.invoke(this.target, args);
System.out.println(args[0]+"买车后买保险,装潢~~~");
return result;
}
}
测试代码:
public static void main(String[] args) {
BuyCar buyCar = new BuyCar();
CGLIBProxyBuyCar cg = new CGLIBProxyBuyCar(buyCar);
BuyCar proxy =(BuyCar) cg.getProxyInstance();
proxy.buyCar("王五");
}
CGLIB 动态代理的坑:
MethodInterceptor的 拦截方法:
// @Param Object o 是代理对象
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//操作前逻辑
//执行invoke时 传入的对象参数必须是被代理的对象
method.invoke(this.target,args);
//执行invokeSuper时,传入的对象参数必须是代理对象,即Object o
//methodProxy.invokeSuper(o,args);
//操作后逻辑
}
错误示范:
@Override
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println(args[0]+"买车前试驾~~~");
//此处传入的对象参数为代理对象
Object result = method.invoke(o, args);
//Object result = methodProxy.invoke(o, args);
//此处对象参数应该传入代理对象o,但是传入的却是被代理对象
//Object result = methodProxy.invokeSuper(this.target, args);
System.out.println(args[0]+"买车后买保险,装潢~~~");
return result;
}
执行测试代码后的结果如下(只截取部分):
出现死循环,导致栈溢出报错~~~~
Caused by: java.lang.StackOverflowError
at java.nio.CharBuffer.<init>(CharBuffer.java:281)
at java.nio.HeapCharBuffer.<init>(HeapCharBuffer.java:70)
at java.nio.CharBuffer.wrap(CharBuffer.java:373)
at sun.nio.cs.StreamEncoder.implWrite(StreamEncoder.java:265)
at sun.nio.cs.StreamEncoder.write(StreamEncoder.java:125)
at java.io.OutputStreamWriter.write(OutputStreamWriter.java:207)
at java.io.BufferedWriter.flushBuffer(BufferedWriter.java:129)
at java.io.PrintStream.write(PrintStream.java:526)
at java.io.PrintStream.print(PrintStream.java:669)
at java.io.PrintStream.println(PrintStream.java:806)
at com.example.awngfei.proxy.CGLIBProxy.CGLIBProxyBuyCar.intercept(CGLIBProxyBuyCar.java:27)
at com.example.awngfei.proxy.CGLIBProxy.BuyCar$$EnhancerByCGLIB$$b0ba1bb4.buyCar(<generated>)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.example.awngfei.proxy.CGLIBProxy.CGLIBProxyBuyCar.intercept(CGLIBProxyBuyCar.java:28)
at com.example.awngfei.proxy.CGLIBProxy.BuyCar$$EnhancerByCGLIB$$b0ba1bb4.buyCar(<generated>)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.example.awngfei.proxy.CGLIBProxy.CGLIBProxyBuyCar.intercept(CGLIBProxyBuyCar.java:28)
at com.example.awngfei.proxy.CGLIBProxy.BuyCar$$EnhancerByCGLIB$$b0ba1bb4.buyCar(<generated>)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.example.awngfei.proxy.CGLIBProxy.CGLIBProxyBuyCar.intercept(CGLIBProxyBuyCar.java:28)
at com.example.awngfei.proxy.CGLIBProxy.BuyCar$$EnhancerByCGLIB$$b0ba1bb4.buyCar(<generated>)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.example.awngfei.proxy.CGLIBProxy.CGLIBProxyBuyCar.intercept(CGLIBProxyBuyCar.java:28)
at com.example.awngfei.proxy.CGLIBProxy.BuyCar$$EnhancerByCGLIB$$b0ba1bb4.buyCar(<generated>)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)