zoukankan      html  css  js  c++  java
  • 面试题:动态代理 未看=!=!=

    1.1.1 动态代理回顾

    1.1.1.1 动态代理的特点

    字节码随用随创建,随用随加载。

    它与静态代理的区别也在于此。因为静态代理是字节码一上来就创建好,并完成加载。

    装饰者模式就是静态代理的一种体现。

    1.1.1.2 动态代理常用的有两种方式

    基于接口的动态代理

    提供者:JDK官方的Proxy类。

    要求:被代理类最少实现一个接口

    基于子类的动态代理

    提供者:第三方的CGLib,如果报asmxxxx异常,需要导入asm.jar

    要求:被代理类不能用final修饰的(最终类)。

    1.1.1.3 使用JDK官方的Proxy类创建代理对象

    此处我们使用的是一个演员的例子:

    在很久以前,演员和剧组都是直接见面联系的。没有中间人环节。

    而随着时间的推移,产生了一个新兴职业:经纪人(中间人),这个时候剧组再想找演员就需要通过经纪人来找了。下面我们就用代码演示出来。

    /**

     * 一个经纪公司的要求:

     * 能做基本的表演和危险的表演

    */

    public interface IActor {

    /**

     * 基本演出

     * @param money

     */

    public void basicAct(float money);

    /**

     * 危险演出

     * @param money

     */

    public void dangerAct(float money);

    }

     

    /**

     * 一个演员

     */

    //实现了接口,就表示具有接口中的方法实现。即:符合经纪公司的要求

    public class Actor implements IActor{

     

    public void basicAct(float money){

    System.out.println("拿到钱,开始基本的表演:"+money);

    }

     

    public void dangerAct(float money){

    System.out.println("拿到钱,开始危险的表演:"+money);

    }

    }

     

    public class Client {

     

    public static void main(String[] args) {

    //一个剧组找演员:

    final Actor actor = new Actor();//直接

     

    /**

     * 代理:

     * 间接。

     * 获取代理对象:

     * 要求:

     *  被代理类最少实现一个接口

     * 创建的方式

     *   Proxy.newProxyInstance(三个参数)

     * 参数含义:

     * ClassLoader:和被代理对象使用相同的类加载器。

     *  Interfaces:和被代理对象具有相同的行为。实现相同的接口。

     *  InvocationHandler:如何代理。

     *   策略模式:使用场景是:

     *   数据有了,目的明确。

     *   如何达成目标,就是策略。

     *  

     */

    IActor proxyActor = (IActor) Proxy.newProxyInstance(

    actor.getClass().getClassLoader(),

    actor.getClass().getInterfaces(),

    new InvocationHandler() {

    /**

     * 执行被代理对象的任何方法,都会经过该方法。

     * 此方法有拦截的功能。

     *

     * 参数:

     * proxy:代理对象的引用。不一定每次都用得到

     * method:当前执行的方法对象

     * args:执行方法所需的参数

     * 返回值:

     * 当前执行方法的返回值

     */

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    String name = method.getName();

    Float money = (Float) args[0];

    Object rtValue = null;

    //每个经纪公司对不同演出收费不一样,此处开始判断

    if("basicAct".equals(name)){

    //基本演出,没有2000不演

    if(money > 2000){

    //看上去剧组是给了8000,实际到演员手里只有4000

    //这就是我们没有修改原来basicAct方法源码,对方法进行了增强

    rtValue = method.invoke(actor, money/2);

    }

    }

    if("dangerAct".equals(name)){

    //危险演出,没有5000不演

    if(money > 5000){

    //看上去剧组是给了50000,实际到演员手里只有25000

    //这就是我们没有修改原来dangerAct方法源码,对方法进行了增强

    rtValue = method.invoke(actor, money/2);

    }

    }

    return rtValue;

    }

    });

    //没有经纪公司的时候,直接找演员。

    // actor.basicAct(1000f);

    // actor.dangerAct(5000f);

     

    //剧组无法直接联系演员,而是由经纪公司找的演员

    proxyActor.basicAct(8000f);

    proxyActor.dangerAct(50000f);

    }

    }

    1.1.1.4 使用CGLibEnhancer类创建代理对象

    还是那个演员的例子,只不过不让他实现接口。

    /**

     * 一个演员

    */

    public class Actor{//没有实现任何接口

     

    public void basicAct(float money){

    System.out.println("拿到钱,开始基本的表演:"+money);

    }

     

    public void dangerAct(float money){

    System.out.println("拿到钱,开始危险的表演:"+money);

    }

    }

     

    public class Client {

    /**

     * 基于子类的动态代理

     * 要求:

     * 被代理对象不能是最终类

     * 用到的类:

     * Enhancer

     * 用到的方法:

     * create(Class, Callback)

     * 方法的参数:

     * Class:被代理对象的字节码

     * Callback:如何代理

     * @param args

     */

    public static void  main(String[] args) {

    final Actor actor = new Actor();

     

    Actor cglibActor = (Actor) Enhancer.create(actor.getClass(),

    new MethodInterceptor() {

    /**

     * 执行被代理对象的任何方法,都会经过该方法。在此方法内部就可以对被代理对象的任何方法进行增强。

     *

     * 参数:

     * 前三个和基于接口的动态代理是一样的。

     * MethodProxy:当前执行方法的代理对象。

     * 返回值:

     * 当前执行方法的返回值

     */

    @Override

    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

    String name = method.getName();

    Float money = (Float) args[0];

    Object rtValue = null;

    if("basicAct".equals(name)){

    //基本演出

    if(money > 2000){

    rtValue = method.invoke(actor, money/2);

    }

    }

    if("dangerAct".equals(name)){

    //危险演出

    if(money > 5000){

    rtValue = method.invoke(actor, money/2);

    }

    }

    return rtValue;

    }

    });

    cglibActor.basicAct(10000);

    cglibActor.dangerAct(100000);

    }

    }

    这个故事(示例)讲完之后,我们从中受到什么启发呢?它到底能应用在哪呢?

    1.1.2 解决案例中的问题

    思路只有一个:使用动态代理技术创建客户业务层的代理对象,在执行CustomerServiceImpl时,对里面的方法进行增强,加入事务的支持。

    /**

     * 用于创建客户业务层对象工厂(当然也可以创建其他业务层对象,只不过我们此处不做那么繁琐)

    */

    public class BeanFactory {

     

    /**

     * 获取客户业务层对象的代理对象

     * @return

     */

    public static ICustomerService getCustomerService() {

    //定义客户业务层对象

    final ICustomerService customerService = new CustomerServiceImpl();

    //生成它的代理对象

    ICustomerService proxyCustomerService = (ICustomerService)

    Proxy.newProxyInstance(customerService.getClass().getClassLoader()

    ,customerService.getClass().getInterfaces(),

    new InvocationHandler() {

    //执行客户业务层任何方法,都会在此处被拦截,我们对那些方法增强,加入事务。

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    String name = method.getName();

    Object rtValue = null;

    try{

    //开启事务

    HibernateUtil.beginTransaction();

    //执行操作

    rtValue = method.invoke(customerService, args);

    //提交事务

    HibernateUtil.commit();

    }catch(Exception e){

    //回滚事务

    HibernateUtil.rollback();

    e.printStackTrace();

    }finally{

    //释放资源.hibernate在我们事务操作(提交/回滚)之后,已经帮我们关了。

    //果他没关,我们在此处关

    }

    return rtValue;

    }

    });

    return proxyCustomerService;

    }

    }

  • 相关阅读:
    JavaScript设计模式_11_中介者模式
    JavaScript设计模式_10_职责链模式
    JavaScript设计模式_09_享元模式
    JavaScript设计模式_08_模板方法模式
    JavaScript设计模式_07_组合模式
    JavaScript设计模式_06_命令模式
    JavaScript设计模式_05_发布订阅模式
    PyTorch Notes | PyTorch 编程实践笔记
    Linux Notes | Linux常用命令行笔记
    CAS邮箱的Express配置
  • 原文地址:https://www.cnblogs.com/shan1393/p/9073973.html
Copyright © 2011-2022 走看看