设计模式——代理模式

代理模式还是比较容易理解,类比我们生活,电视机厂家生成电视,然后电视机厂家把电视剧买给老百姓。但是老百姓一般是从代理商家那儿买电视剧。其中电视剧厂家就是真正拥有货源的,被叫做真实角色。代理商家其实是没有货源的,不过代理商家在卖电视剧的时候,可以搞很多活动以增加销量,代理商家就是代理角色。

代理模式分为静态代理和动态代理两种。

静态代理:

静态代理一般分为三个角色:

1.抽象角色:一般是接口或者抽象类,里面定义了方法

2.真实角色:需要被代理的类

3.代理对象:代理真实角色,扩展更多的功能。

代码:

抽象角色: 里面定义了需要被代理的方法

public interface TargetObject {

    public void sendMes();
}

真实角色:实现了抽象角色

public class ReallyObject implements TargetObject {
	@Override
    public void sendMes() {
        System.out.println("真实对象执行了sendMes()");
    }
}

代理对象:在真实角色上,扩展了更多的功能

public class ProxyObject implements TargetObject {

    private ReallyObject reallyObject;

    public ProxyObject(ReallyObject reallyObject) {
        this.reallyObject = reallyObject;
    }

    @Override
    public void sendMes() {
        reallyObject.sendMes();
        //扩展的内容
        System.out.println("发送信息完毕,请及时接受");
    }
}

测试:

public static void main(String[] args) {
        ReallyObject reallyObject = new ReallyObject();
        ProxyObject proxyObject = new ProxyObject(reallyObject);
        proxyObject.sendMes();
    }

总结:从上述代码,我们也看到了,假如抽象角色改变,那么真实角色和代理角色都必须改变。在实际开发这样使用的话,就非常麻烦了,所有这种方法,我们没怎么使用。

动态代理

动态代理分为jdk动态代理以及CGLIB代理。CGLIB是一个开源的项目。

JDK动态代理

jdk动态代理,怎能代理实现了接口的类,我们需要使用到InvocationHandler类的invoke方法(代理类执行方法的时候,其实是执行invoke方法),所有我们需要重写InvocationHandler类。下面我们以模拟发送短信为例

发送短信接口

public interface SmsService {
    void send(String s);
}

发送短信实现类

public class SmsServiceImpl implements SmsService {
    
    @Override
    public void send(String s) {
        System.out.println("开始发送短信:" + s);
    }
}

实现InvocationHandler类,重写invoke方法。注意 我们在new的时候,需要把真实对象(SmsServiceImpl)传入构造函数.这样invoke方法里面才能调用真实对象的方法。

public class OverrideInvocationHandler implements InvocationHandler {

    private Object target;

    public OverrideInvocationHandler(Object target) {
        this.target = target;
    }

    //当代理对象调用方法的时候,其实是调用InvocationHandler的invoke方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("发送短信之前");
        Object invoke = method.invoke(target, args);
        System.out.println("发送短信之后");
        return invoke;
    }

测试:

public class TestDynamic {
    public static void main(String[] args) {
        //通过真实对象获取代理对象
        SmsServiceImpl smsService = new SmsServiceImpl();
        SmsService service = (SmsService) Proxy.newProxyInstance(smsService.getClass().getClassLoader(),
                smsService.getClass().getInterfaces(),
                new OverrideInvocationHandler(smsService));
        service.send("1234");
    }
}

总结:jdk动态代理必须实现接口,接口变动的话,就需要变动其实现类。而且其所有的代码在编译的时候就生成了一个个class文件。

CGLIB动态代理
CGLIB是一个开源框架,所有我们需要引入jar包

<!-- https://mvnrepository.com/artifact/org.ow2.asm/asm -->
<dependency>
    <groupId>org.ow2.asm</groupId>
    <artifactId>asm</artifactId>
    <version>7.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

实现CGLIB动态代理需要用到MethodIntercptot类和Enhancer类(代理增强类)。

CGLIB主要使用的是继承,可以直接代理其真实对象。不过效率没有JDK动态代理高。而且是在运行期间,由JVM生成一个个字节码,这和JDK代理是不一样的。

代码:模拟阿里发送短信

真实对象

public class AliSendService {

    public void send(String code) {
        System.out.println("发送阿里短信:" + code);
    }
}

实现MethodInvocationIntercptor类,并重新其方法。

//重写intercept方法
public class CglibDynamicInterception implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("发送短信之前");
        Object o1 = methodProxy.invokeSuper(o, objects);
        System.out.println("返送短信之后");
        return o1;
    }
}

实现创建代理类,使用Enhancer类

public class ProxyFactory {

    /**
     * 获取代理对象
     * @param clazz
     * @return
     */
    public static Object getInstance(Class<?> clazz) {
        //代理增强类
        Enhancer enhancer = new Enhancer();
        //设置拦截器
        enhancer.setCallback(new CglibDynamicInterception());
        //设置类加载器
        enhancer.setClassLoader(clazz.getClassLoader());
        //设置被代理类
        enhancer.setSuperclass(clazz);
        //创建代理对象
        return enhancer.create();
    }
}

测试:

public class CglibTest {

    public static void main(String[] args) {
        AliSendService sendService = (AliSendService) ProxyFactory.getInstance(AliSendService.class);
        sendService.send("1234");

    }
}

总结,CGLIB ,是通过是代理的时候,生成子类来拦截被代理对象的执行方法。是在程序运行期间,由JVM生成class文件。可以直接代理真实对象。比如在SpringAOP模块,如何被真实对象实现了接口,则默认采用JDK动态代理,如果没有接口,则采用CGLIB动态代理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值