静态代理
被代理对象实现的接口:
/**
* @author xwm
* @email 2825902051@qq.com
* @date 2021/9/13 0013
* @time 18:51
*/
public interface Computer {
//出售电脑
double sellComputer(double price);
}
被代理对象:
public class Lenovo implements Computer{
@Override
public double sellComputer(double price) {
System.out.println("执行目标对象 do sellComputer() 方法\n花费了"+price+"元");
return price;
}
}
使用静态代理代理Lenovo对象:
package Proxy;
/**
* @author xwm
* @email 2825902051@qq.com
* @date 2021/9/13 0013
* @time 18:55
*/
public class StaticProxy implements Computer{
private Lenovo target;
public StaticProxy(Lenovo target) {
this.target = target;
}
@Override
public double sellComputer(double price) {
System.out.println("static proxy...");
return target.sellComputer(price);
}
public static void main(String[] args) {
Lenovo lenovo = new Lenovo();
StaticProxy staticProxy = new StaticProxy(lenovo);
double price=4000.0;
staticProxy.sellComputer(price);
}
}
总结
- 静态代理在编译的时候·就生成了代理对象,而动态代理需要在运行时生成代理对象的字节码来构造对象。
- 粒度较大,修改参数和返回值需要在调用方法前后,并且如果需要添加业务逻辑要先写死在代理对象的方法中,时机不好控制,不灵活。
JDK动态代理
实现InvocationHandler接口并重写方法
package Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* @author xwm
* @email 2825902051@qq.com
* @date 2021/9/13 0013
* @time 19:41
*/
public class JdkProxy implements InvocationHandler {
private Object target;
public JdkProxy(Object target) {
this.target = target;
}
public Object getProxyInstance(){
Object o = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
return o;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("jdk proxy ...");
System.out.println("拿到方法参数为:"+args[0]);
double invoke = (double) method.invoke(target, args);
invoke=invoke-5000.0;
System.out.println("返回值为:"+invoke);
System.out.println("jdk proxy ...");
return invoke;
}
public static void main(String[] args) {
JdkProxy jdkProxy =new JdkProxy(new Lenovo());
Computer proxyInstance = (Computer)jdkProxy.getProxyInstance();
double v = proxyInstance.sellComputer(10000.0);
System.out.println("实际费用为"+v);
}
}
运行结果:
总结
- jdk动态代理通过生成一个和目标对象有相同接口,并且类加载器相同的字节码,然后通过反射创建一个和目标对象有相同特征的代理对象,所以需要在运行时才能创建。
- 代理的粒度较细,并且不需要像静态代理一样每个方法都要写死业务逻辑,可以修改参数和返回值,比较灵活
- 由于生成的代理对象已经继承了Proxy所以不能在继承别的类,并且目标对象必须有接口实现
Cglib动态代理
package Proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.Date;
/**
* @author xwm
* @email 2825902051@qq.com
* @date 2021/9/13 0013
* @time 19:03
*/
public class CglibProxy implements MethodInterceptor {
private Object target;
public CglibProxy(Object target) {
this.target = target;
}
public Object getProxyInstance(){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// 回调方法
enhancer.setCallback(this);
// 创建代理对象
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib proxy ...");
System.out.println("收到的进购费用为:"+objects[0]);
double money=3000.0;
Object o1 = methodProxy.invokeSuper(o, new Object[]{money});
System.out.println("购买时间为:"+new Date());
System.out.println("cglib proxy ...");
return o1;
}
public static void main(String[] args) {
Lenovo lenovo = new Lenovo();
Lenovo proxyInstance = (Lenovo) new CglibProxy(lenovo).getProxyInstance();
double v = proxyInstance.sellComputer(4000.0);
System.out.println("实际费用为"+v);
}
}
运行结果:
总结
- 目标类必须是公共的不被finall修饰的,并且被代理对象的方法也不能被final修饰。
- 通过继承目标对象来重写里面的方法