设计模式 代理模式(Proxy)

博文目录


静态代理模式

public interface Singer {
	void sing();
}
public class SHESinger implements Singer {
	@Override
	public void sing() {
		System.out.println("SHE 唱《中国话》");
	}
}
// 实现某接口并持有该接口的引用
public class Proxy implements Singer {
	private Singer singer;
	public Proxy() {
		// 无需传入, 关系明确, 直接内定
		this.singer = new SHESinger();
	}
	@Override
	public void sing() {
		System.out.println("演出前谈合同");
		singer.sing();
		System.out.println("演出后收钱");
	}
}
public class Test {
	public static void main(String[] args) {
		Singer proxy = new Proxy();
		proxy.sing();
	}
}
演出前谈合同
SHE 唱《中国话》
演出后收钱

静态代理模式和装饰器模式的异同

代理模式和装饰器模式的区别
Java中“装饰模式”和“代理模式”有啥区别?

两者都是一个类实现某个接口并持有该接口的引用

代理模式: 代理和被代理两者的关系很明确, 使用者无需关注被代理对象. 如 dubbo 的 rpc 访问
装饰模式: 主要是给某个主体扩展功能, 功能顺序随意且可叠加. 如 dubbo 的 mock,cluster,failover 等功能

动态代理模式

jdk

Java:聊聊JDK和CGLib动态代理实现和区别

JDK动态代理主要涉及java.lang.reflect包下边的两个类:Proxy和InvocationHandler。其中,InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态地将横切逻辑和业务逻辑编织在一起。

代理某个对象, 利用反射生成一个接口的实现类, 在调用具体方法前调用 InvocationHandler 来处理

通过这种方式生成的代理类都会继承 Proxy, Java 是单继承, 所以只能实现接口了, 所以说 jdk 只适用于接口方式的代理

public class SingerInvocationHandler implements InvocationHandler {

    private Singer singer;

    public SingerInvocationHandler(Singer singer) {
        this.singer = singer;
    }

    /**
     * @param proxy  代理对象(用来代理singer)
     * @param method 被代理的方法
     * @param args   被代理的方法的参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("演出前商谈");
        // 这里切记 invoke 的对象不是 target 而是 入参proxy
        // 入参proxy 是生成的代理对象实例, 调用其method会被代理到invoke方法, 从而导致循环调用, 堆栈溢出
        Object result = method.invoke(singer, args);
        System.out.println("演出后分收钱");
        return result;
//		return proxy;
    }

    public static Singer getProxy(Singer singer) {
        return (Singer) Proxy.newProxyInstance(singer.getClass().getClassLoader(), singer.getClass().getInterfaces(), new SingerInvocationHandler(singer));
    }

}
public class Test {
	public static void main(String[] args) throws Throwable {
		Singer singer = new SHESinger();
		Singer proxy = SingerInvocationHandler.getProxy(singer);
		proxy.sing();
	}
}
演出前商谈
SHE 唱《中国话》
演出后分收钱

cglib (code generator library)

CGLIB是一个基于ASM的字节码生成库,它允许我们在运行时对字节码进行修改和动态生成。CGLIB通过继承方式实现代理,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势织入横切逻辑。

创建子类继承现有类, 所以要代理的类不能加 final, 子类要覆盖父类的方法(super.method()前后添加扩展逻辑), 所以要代理的方法不能加 final, 加了后子类不能覆盖该方法, 所以调用的直接就是父类定义的方法了, 丢失了扩展逻辑

<dependency>
	<groupId>cglib</groupId>
	<artifactId>cglib</artifactId>
	<version>3.3.0</version>
</dependency>
public class SHESingerMethodInterceptor implements MethodInterceptor {
    /**
     * @param o 被代理的对象
     * @param method 被拦截的方法
     * @param objects 被拦截的方法的参数
     * @param methodProxy 要触发父类的方法对象
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if ("sing".equals(method.getName())) {
            System.out.println("演出前商谈");
            // invokeSuper 而不是 invoke
            Object result = methodProxy.invokeSuper(o, objects);
            System.out.println("演出后分收钱");
            return result;
        }
        return null;
    }
}
public class Test {
    public static void main(String[] args) throws Throwable {
        // 通过CGLIB动态代理获取代理对象的过程
        Enhancer enhancer = new Enhancer();
        // 设置enhancer对象的父类
        enhancer.setSuperclass(SHESinger.class);
        // 设置enhancer的回调对象
        enhancer.setCallback(new SHESingerMethodInterceptor());
        // 创建代理对象
        SHESinger proxy = (SHESinger) enhancer.create();
        // 通过代理对象调用目标方法
        proxy.sing();
    }
}
演出前商谈
SHE 唱《中国话》
演出后分收钱
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值