设计模式 - 代理模式

使用代理模式主要有两个目的:一保护目标对象,二增强目标对象

静态代理

静态代理类 -- 代表是在代码编译阶段已经生产的代理类。

与被代理类实现相同接口

模拟火车站买票 -- 静态代理类模拟火车票售卖点

public interface SellTicket {
    void sell();
}

public class TrainStation implements SellTicket {
    @Override
    public void sell() {
        System.out.println("火车站卖票");
    }
}

public class StaticProxy implements SellTicket {
    private SellTicket sellTicket;

    public StaticProxy(SellTicket sellTicket) {
        this.sellTicket = sellTicket;
    }

    @Override
    public void sell() {
        System.out.println("黄牛 : 静态代理类 -- 收取手续费");
        sellTicket.sell();
    }
}


public class ProxyTest {
    public static void main(String[] args) {
        SellTicket sellTicket = new StaticProxy(new TrainStation());
        sellTicket.sell();
    }
}

public class ProxyTest {
    public static void main(String[] args) {
        SellTicket sellTicket = new StaticProxy(new TrainStation());
        sellTicket.sell();
    }
}

运行结果:

黄牛 : 静态代理类 -- 收取手续费
火车站卖票

动态代理类

动态代理类 -- 代表是在代码运行期间生成的代理类

动态代理类:1.JDK生成的动态代理类 2.CGLIB生成的动态代理类

JDK 动态代理类

JDK生成动态代理类用一个限制,必须被代理的类具有接口。否则不能代理

public class JDKProxyFactory {

    public static SellTicket getProxy(SellTicket sellTicket) {
        SellTicket sellTicketProxy = (SellTicket) Proxy.newProxyInstance(
                //在运行期间生成代理类,则需要类加载器
                sellTicket.getClass().getClassLoader(),
                //生成的代理类需要增强哪些接口的方法
                sellTicket.getClass().getInterfaces(),
                //当代理对象的方法被调用时,被handler的invoke方法接受处理
                new InvocationHandler() {
                    /**
                     * @param proxy 代理对象本身 = sellTicketProxy
                     * @param method 被调用的方法
                     * @param args  被调用的方法传入的参数
                     * @return obj 返回值,void方法时为null
                     */
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("黄牛 2: JDK动态代理类 -- 收取手续费");
                        Object obj = method.invoke(sellTicket, args);
                        return obj;
                    }
                }
        );
        return sellTicketProxy;
    }
}

public class ProxyTest {
    public static void main(String[] args) {
        SellTicket jdkProxy = JDKProxyFactory.getProxy(new TrainStation());
        jdkProxy.sell();
    }
}

运行结果:

黄牛 2: JDK动态代理类 -- 收取手续费
火车站卖票

CGLIB 动态代理类

cglib可以在代理没有接口的普通类,原理:生成的代理类为目标类的子类,所以如果被代理的类是final类型,或者方法时final修饰的则不能被代理.

因为使用CGLIB,则需要导入依赖,如果是springboot项目则不需要单独导入,springboot的依赖已经自带了

       <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>2.2.2</version>
        </dependency>
public class CglibProxyFactory {
    public static  <T> T getProxy(T t) {
        Enhancer enhancer = new Enhancer();
        //设置生成谁的子类
        enhancer.setSuperclass(t.getClass());
        enhancer.setCallback(new MethodInterceptor() {
            /**
             *当代理对象的方法被调用时,被intercept方法接受处理
             */
            @Override
            public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("黄牛 3: CGLIB动态代理类 -- 收取手续费");
                Object obj = method.invoke(t, args); // 用方法反射调用目标
            //  Object obj = methodProxy.invoke(t, args); // 内部没有用反射, 需要目标 (spring)
            //  Object result = methodProxy.invokeSuper(o, args); // 内部没有用反射, 需要代理
                return obj;
            }
        });
        return (T) enhancer.create();
    }
}

    public static void main(String[] args) {
        System.out.println("--------------------------------");
        SellTicket cglibProxy = CglibProxyFactory.getProxy(new TrainStation());
        cglibProxy.sell();
    }

运行结果:

黄牛 3: CGLIB动态代理类 -- 收取手续费
火车站卖票

使用methodProxy.invoke(), methodProxy.invokeSuper()都没有使用反射的机制进行方法调用,所以效率会高于method.invoke()

总结:

被代理类是存在接口的就使用JDK生成代理类,如果是没有接口的就使用CGLIB生成代理类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值